contents
related file
- cpython/Objects/funcobject.c
- cpython/Include/funcobject.h
- cpython/Objects/clinic/funcobject.c.h
memory layout
Everything is an object in Python, including functions. A function is defined as PyFunctionObject at the C level
def f(a, b=2): print(a, b) >>> type(f) function
the type function indicates the user-defined method/classes, for builtin_function_or_method please refer to method
field
Let's figure out the meaning of each field in PyFunctionObject
func_code
The func_code field stores an instance of PyCodeObject, which contains information about a code block.
A code block contains the Python virtual machine's instructions, argument count, argument body, etc.
I will explain PyCodeObject in another article
>>> f.__code__ <code object f at 0x1078015d0, file "<stdin>", line 1>
func_globals
The global namespace attached to the function object
>>> type(f.__globals__) <class 'dict'> >>> f.__globals__ {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'f': <function f at 0x10296eac0>}
func_defaults
A tuple that stores all the default arguments of the function object
func_kwdefaults
The field func_kwdefaults is a Python dictionary that stores keyword-only arguments with default values
def f2(a, b=4, *x, key=111): print(a, b, x, key) >>> f2.__kwdefaults__ {'key': 111}
func_closure
The func_closure field is a tuple that indicates all the enclosing levels of the current function object
def wrapper(func): def func_inside(*args, **kwargs): print("calling func", func) func(args, kwargs) print("call done") return func_inside @wrapper def my_func(): print("my func") >>> my_func.__closure__ (<cell at 0x10911c928: function object at 0x1092b3c40>,) >>> my_func <function wrapper.<locals>.func_inside at 0x1092b3b40> >>> wrapper <function wrapper at 0x1092b3cc0>
let's see an example with more _closure_
def wrapper2(func1): def func_inside1(func2): def func_inside2(*args2, **kwargs2): print("calling func1", func1) r = func1(*args2, **kwargs2) print("calling func2", func2) r = func2(*args2, **kwargs2) print("call done") return r print("func_inside2.__closure__", func_inside2.__closure__) return func_inside2 print("func_inside1.__closure__", func_inside1.__closure__) return func_inside1 @wrapper2 def my_func2(): print("my func2") def func3(): print("func3") # m = my_func() inside2 = my_func2(func3) print("----------------") inside2() # output (<cell at 0x100e69eb8: function object at 0x100e6fea0>,) func_inside1.__closure__ (<cell at 0x1087e9408: function object at 0x1087f1ae8>,) func_inside2.__closure__ (<cell at 0x1087e9408: function object at 0x1087f1ae8>, <cell at 0x1087e9498: function object at 0x1087f1bf8>) ---------------- calling func1 <function my_func2 at 0x1087f1ae8> my func2 calling func2 <function func3 at 0x1087f1bf8> func3 call done
func_doc
Usually, it's a unicode object for documentation
def f(): """ I am the document """ pass print(f.__doc__)
func_name
The name of the PyFunctionObject object
def i_have_a_very_long_long_long_name(): pass print(i_have_a_very_long_long_long_name.__name__) # output # i_have_a_very_long_long_long_name
func_dict
The func_dict field stores the attributes of the function object
>>> f.__dict__ {} >>> f.a = 3 >>> f.__dict__ {'a': 3}
func_module
The func_module field indicates the module to which the PyFunctionObject is attached
>>> f.__module__ '__main__' >>> from urllib.parse import urlencode >>> urlencode.__module__ 'urllib.parse'
func_annotations
you can read PEP 3107 -- Function Annotations for more detail
def a(x: "I am a int" = 3, y: "I am a float" = 4) -> "return a list": pass >>> a.__annotations__ {'x': 'I am a int', 'y': 'I am a float', 'return': 'return a list'}
func_qualname
It's used for nested class/function representation. It contains a dotted path leading to the object from the module top-level. Refer to PEP 3155 -- Qualified name for classes and functions for more detail
def f(): def g(): pass return g >>> f.__qualname__ 'f' >>> f().__qualname__ 'f.<locals>.g'
