Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does __self__ of built-in functions return the builtin module it belongs to?

Methods have an attribute, __self__, that holds the instance to be passed when the underlying function gets invoked. Apparently, so do built-in functions.

In Python 3, they hold the module object:

>>> len.__self__
<module 'builtins' (built-in)>
>>> sys.getrefcount.__self__  # also for other builtin modules
<module 'sys' (built-in)>

In Python 2, on the other hand, they hold None:

>>> type(len.__self__)
<type 'NoneType'>
>>> sys.getrefcount.__self__
<type 'NoneType'>

Does anyone know why there's a discrepancy here? In addition to that, why do these even have a __self__ and aren't like Python level module functions that lack a __self__ attribute:

>>> from pprint import pprint
>>> pprint.__self__
AttributeError: 'function' object has no attribute '__self__'
like image 361
Dimitris Fasarakis Hilliard Avatar asked Mar 20 '17 16:03

Dimitris Fasarakis Hilliard


People also ask

What are built-in functions in Python?

In addition to built-in functions, a large number of pre-defined functions are also available as a part of libraries bundled with Python distributions. These functions are defined in modules are called built-in modules. Built-in modules are written in C and integrated with the Python shell.

What are built-in modules in Python?

These functions are defined in modules are called built-in modules. Built-in modules are written in C and integrated with the Python shell. Each built-in module contains resources for certain system-specific functionalities such as OS management, disk IO, etc.

What are built-in functions in C?

Built-in functions are similar to operation codes in that they perform operations on data you specify. Built-in functions can be used in expressions. Additionally, constant-valued built-in functions can be used in named constants. These named constants can be used in any specification.

What are the advantages of using built-in functions?

In general, the arguments of the built-in function are similar to the factor 1 and factor 2 fields of an operation code. Another useful feature of built-in functions is that they can simplify maintenance of your code when used on the definition specification. The following example demonstrates this feature.


1 Answers

I believe I've found the reason for the discrepancy thanks to issue14003. It seems it is due to a change in the module creation API from Python 2 to 3.

In Python 2, during the construction of modules with Py_InitModule4, a PyObject *self argument was available that could have the value of None if writters of extention modules wished, as documented:

If self is non-NULL, it will be passed to the functions of the module as their (otherwise NULL) first parameter

Most of the built-in standard library modules apparently chose that path and as such the result of builtin_function.__self__ is None:

mod = Py_InitModule4("__builtin__", builtin_methods,
                     builtin_doc, (PyObject *)NULL,
                     PYTHON_API_VERSION);

In Python 3, the API for creating modules changed and that option disappeared. The function for creating modules, PyModule_Create2, doesn't take a self argument that's allowed to be None. Instead, it calls PyModule_AddFunctions (which calls the internal _add_methods_to_object to add the functions to the module) and unconditionally sets the __self__ attribute on the builtin functions to be the module.

So that's why for len the builtins module is returned. AFAIK, it isn't used anywhere inside the function body so it's purpose isn't special in any way.


Props to @user2357112 for making me feel silly, builtin_method and builtin_function are actually the same struct so it makes sense for builtin functions to share the __self__ attribute found in methods.

The function type, on the other hand, really has no point in having it since it isn't shared in any way with the method type.

like image 179
Dimitris Fasarakis Hilliard Avatar answered Oct 16 '22 13:10

Dimitris Fasarakis Hilliard