forked from zpoint/CPython-Internals
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfunc.md
More file actions
251 lines (174 loc) · 5.47 KB
/
Copy pathfunc.md
File metadata and controls
251 lines (174 loc) · 5.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# 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 function, a function is defined as **PyFunctionObject** in 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)

# field
let's figure out the meaning of each field in the **PyFunctionObject**
## func_code
**func_code** field stores an instance of **PyCodeObject**, which contains information of a code block
A code block must contain python virtual machine's instruction, argument number, argument
body and etc
I will explain **PyCodeObject** in other article
```python3
>>> f.__code__
<code object f at 0x1078015d0, file "<stdin>", line 1>
```
## func_globals
the global namespace attached to the function object
```python3
>>> 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 stores all the default argument of the function object
```python3
>>> f.__defaults__
(2,)
```
## func_kwdefaults
field **func_kwdefaults** is a python dictionary, which stores the [keyword-only argument](https://www.python.org/dev/peps/pep-3102/) with default value
```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, indicate all the enclosing level 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__
(<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_\_
```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
(<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 an **unicode** object for explanation
```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
**func_dict** field stores the attribute of the function object
```python3
>>> f.__dict__
{}
>>> f.a = 3
>>> f.__dict__
{'a': 3}
```
## func_module
**func_module** field indicate the module which the **PyFunctionObject** attached to
```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 [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.<locals>.g'
```