# func # contents * [related file](#related-file) * [memory layout](#memory-layout) * [field](#field) * [func_code](#func_code) * [func_globals](#func_globals) * [func_defaults](#func_defaults) * [func_kwdefaults](#func_kwdefaults) * [func_closure](#func_closure) * [func_doc](#func_doc) * [func_name](#func_name) * [func_dict](#func_dict) * [func_module](#func_module) * [func_annotations](#func_annotations) * [func_qualname](#func_qualname) # 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 ```python3 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](https://github.com/zpoint/CPython-Internals/blob/master/BasicObject/method/method.md) ![layout](https://github.com/zpoint/CPython-Internals/blob/master/BasicObject/func/layout.png) # 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 ```python3 >>> f.__code__ ", line 1> ``` ## func_globals The global namespace attached to the function object ```python3 >>> type(f.__globals__) >>> f.__globals__ {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': , 'f': } ``` ## func_defaults A tuple that stores all the default arguments of the function object ```python3 >>> f.__defaults__ (2,) ``` ## func_kwdefaults The field **func_kwdefaults** is a Python dictionary that stores [keyword-only arguments](https://www.python.org/dev/peps/pep-3102/) with default values ```python3 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 ```python3 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__ (,) >>> my_func .func_inside at 0x1092b3b40> >>> wrapper ``` let's see an example with more _\_closure_\_ ```python3 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 (,) func_inside1.__closure__ (,) func_inside2.__closure__ (, ) ---------------- calling func1 my func2 calling func2 func3 call done ``` ## func_doc Usually, it's a **unicode** object for documentation ```python3 def f(): """ I am the document """ pass print(f.__doc__) ``` ## func_name The name of the **PyFunctionObject** object ```python3 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 ```python3 >>> f.__dict__ {} >>> f.a = 3 >>> f.__dict__ {'a': 3} ``` ## func_module The **func_module** field indicates the module to which the **PyFunctionObject** is attached ```python3 >>> f.__module__ '__main__' >>> from urllib.parse import urlencode >>> urlencode.__module__ 'urllib.parse' ``` ## func_annotations you can read [PEP 3107 -- Function Annotations](https://www.python.org/dev/peps/pep-3107/) for more detail ```python3 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](https://www.python.org/dev/peps/pep-3155/) for more detail ```python3 def f(): def g(): pass return g >>> f.__qualname__ 'f' >>> f().__qualname__ 'f..g' ```