Notice: While Javascript is not essential for this website, your interaction with the content will be limited. Please turn Javascript on for the full experience.

PEP 576 -- Rationalize Built-in function classes

PEP:576
Title:Rationalize Built-in function classes
Author:Mark Shannon <mark at hotpy.org>
Status:Draft
Type:Standards Track
Created:10-May-2018
Python-Version:3.8
Post-History:17-May-2018

Abstract

Extend the classes for built-in functions and methods to be more like Python functions. Specifically, built-in functions and methods will gain access to the module they are declared in, and built-in methods will have access to the class they belong to. This will allow tools like Cython to use the standard built-in function and method classes, thus gaining performance parity with built-in functions like len or print. Performance of existing code is not expected to change significantly.

One new function will be added to the C API to allow third-party code to create built-in functions in an efficient and portable manner.

Motivation

Currently third-party module authors face a dilemma when implementing functions in C. Either they can use one of the pre-existing built-in function or method classes or implement their own custom class in C. The first choice causes them to lose the ability to access module-level data; the second choice is an additional maintenance burden and, more importantly, has a significant negative impact on performance.

This PEP aims to allow authors of third-party C modules, and tools like to Cython, to utilise the pre-existing built-in function or method classes without a loss of capabilities relative to a function implemented in Python.

Enhanced access to the function's enviroment

Built-in functions will gain efficient access to the module in which they are declared, and if declared in a class, efficient access to that class as well.

Performance

No significant change is expected.

Introspection

No changes to built-in functions are required to support introspection.

The inspect.Signature.from_callable() function computes the signature of a callable. If an object has a __signature__ property, then inspect.Signature.from_callable() simply returns that. If a builtin-callable has a __text_signature__ then the __signature__ is created from that. This means that 3rd party builtin-functions can implement __text_signature__ if sufficient, and the more expensive __signature__ if necessary.

New classes and changes to existing classes

Python visible changes

  1. A new built-in class, builtin_function, will be added.
  2. types.BuiltinFunctionType will refer to builtin_function not builtin_function_or_method.
  3. Instances of the builtin_function class will retain the __module__ property of builtin_function_or_method and gain the func_module and func_globals properties. The func_module allows access to the module to which the function belongs. Note that this is different from the __module__ property which merely returns the name of the module. The func_globals property is equivalent to func_module.__dict__ and is provided to mimic the Python function property of the same name.
  4. The method_descriptor class will become a sub-class of the new builtin_function class.
  5. When binding a method_descriptor instance to an instance of its owning class, a bound_method will be created instead of a builtin_function_or_method. This means that the method_descriptors now mimic the behaviour of Python functions more closely. In other words, [].append becomes a bound_method instead of a builtin_function_or_method.

Note that method_descriptor instances will only have access to their module if their __objclass__ class has access to its module. If PEP 573 is approved, then that will be possible.

C API changes

  1. A new function PyBuiltinFunction_New(PyMethodDef *ml, PyObject *module) is added to create built-in functions.
  2. PyCFunction_NewEx() and PyCFunction_New() are deprecated and will return a PyBuiltinFunction if able, otherwise a builtin_function_or_method.

Retaining backwards compatibility in the C API and ABI

The PyCFunction_Type object will continue to exist for backwards compatibility in the ABI, but no instances of it would be created in the interpreter or the standard library.

Internal C changes

The new C struct for built-in functions is:

typedef struct {
    PyObject_HEAD
    PyMethodDef m_ml; /* Description of the C function to call */
    PyObject    *m_module; /* The func_module attribute, must be an actual module */
    PyObject    *m_weakreflist; /* List of weak references */
} PyBuiltinFunctionObject;

and the C struct for method_descriptors changes to:

typedef struct {
    PyBuiltinFunctionObject base;
    PyTypeObject *m_objclass; /* The __objclass__ attibute */
} PyMethodDescrObject;

Possible Extensions

Callables for operators, like int.__add__, could become instances of the method_descriptor class, instead of the slot_wrapper class. This would further reduce the number of classes representing built-in callables, but is not necessary to fulfil the above requirements.

If the slot__wrapper class were removed, then two new METH_ flags would need to be added. The new flags would be METH_OO and METH_TRIO for two and three argument operators respectively.

Alternative Suggestions

PEP 575 <https://www.python.org/dev/peps/pep-0575/> is an alternative approach to solving the same problem as this PEP.

Source: https://github.com/python/peps/blob/master/pep-0576.rst