函數(shù)是任何一門編程語(yǔ)言都具備的基本元素,,它可以將多個(gè)動(dòng)作組合起來(lái),,一個(gè)函數(shù)代表了一系列的動(dòng)作,。而且在調(diào)用函數(shù)時(shí)會(huì)干什么來(lái)著,,沒錯(cuò),,要?jiǎng)?chuàng)建棧幀,,用于函數(shù)的執(zhí)行,。 那么下面就來(lái)看看函數(shù)在 C 中是如何實(shí)現(xiàn)的,,生得一副什么模樣。 Python中一切皆對(duì)象,,函數(shù)也不例外,。函數(shù)這種抽象機(jī)制在底層是通過PyFunctionObject對(duì)象實(shí)現(xiàn)的,位于funcobject.h 中,。 我們來(lái)實(shí)際獲取一下這些成員,,看看它們?cè)?Python 中是如何表現(xiàn)的。
1)func_code:函數(shù)的字節(jié)碼 def foo(a, b, c): pass
code = foo.__code__ print(code) # <code object foo at ......> print(code.co_varnames) # ('a', 'b', 'c')
2)func_globals:global名字空間 def foo(a, b, c): pass
name = "古明地覺" print(foo.__globals__) # {......, 'name': '古明地覺'} # 拿到的其實(shí)就是外部的 global名字空間 print(foo.__globals__ == globals()) # True
3)func_defaults:函數(shù)參數(shù)的默認(rèn)值 def foo(name="古明地覺", age=16): pass
# 打印的是默認(rèn)值 print(foo.__defaults__) # ('古明地覺', 16)
def bar(): pass
# 沒有默認(rèn)值的話,,__defaults__ 為 None print(bar.__defaults__) # None
4)func_kwdefaults:只能通過關(guān)鍵字參數(shù)傳遞的 "參數(shù)" 和 "該參數(shù)的默認(rèn)值" 組成的字典 def foo(name="古明地覺", age=16): pass
# 打印為 None,,這是因?yàn)殡m然有默認(rèn)值 # 但并不要求必須通過關(guān)鍵字參數(shù)的方式傳遞 print(foo.__kwdefaults__) # None
def bar(*, name="古明地覺", age=16): pass
print(bar.__kwdefaults__) # {'name': '古明地覺', 'age': 16}
如果在前面加上一個(gè) *,就表示后面的參數(shù)必須通過關(guān)鍵字的方式傳遞,。因?yàn)槿绻煌ㄟ^關(guān)鍵字參數(shù)傳遞的話,,那么無(wú)論多少個(gè)位置參數(shù)都會(huì)被 * 接收,無(wú)論如何也不可能傳遞給name,、age,。 我們經(jīng)常會(huì)看到 *args,這是因?yàn)槲覀冃枰瘮?shù)調(diào)用時(shí)傳遞過來(lái)的值,,而通過 args 能以元組的形式來(lái)拿到這些值,。但是這里我們不需要,我們只是希望后面的參數(shù)必須通過關(guān)鍵字參數(shù)傳遞,,因此前面寫一個(gè) * 即可,,當(dāng)然寫 *args 也是可以的,。 5)func_closure:閉包對(duì)象 def foo(): name = "古明地覺" age = 16
def bar(): nonlocal name nonlocal age
return bar
# 查看的是閉包里面 nonlocal 的值,,由于有兩個(gè) nonlocal # 所以foo().__closure__ 是一個(gè)包含兩個(gè)元素的元組 print(foo().__closure__) """ (<cell at 0x000001FD1D3B02B0: int object at 0x00007FFDE559D660>, <cell at 0x000001FD1D42E310: str object at 0x000001FD1D3DA090>) """
print(foo().__closure__[0].cell_contents) # 16 print(foo().__closure__[1].cell_contents) # 古明地覺
注意:查看閉包屬性我們使用的是內(nèi)層函數(shù),不是外層的 foo,。 6)func_doc:函數(shù)的 doc def foo(): """ hi,,歡迎來(lái)到我的小屋 遇見你真好 """ pass
print(foo.__doc__) """
hi,歡迎來(lái)到我的小屋 遇見你真好 """
6)func_name:函數(shù)的名字 def foo(name, age): pass
print(foo.__name__) # foo
當(dāng)然不光是函數(shù),方法,、類,、模塊都有自己的名字,
import numpy as np
print(np.__name__) # numpy print(np.ndarray.__name__) # ndarray print(np.array([1, 2, 3]).transpose.__name__) # transpose
7)func_dict:函數(shù)的屬性字典 因?yàn)楹瘮?shù)在底層也是由一個(gè)類實(shí)例化得到的,,所以它可以有自己的屬性字典,,只不過這個(gè)字典一般為空。 def foo(name, age): pass
print(foo.__dict__) # {}
當(dāng)然啦,,我們也可以整點(diǎn)騷操作:
所以雖然叫函數(shù),,但它也是由某個(gè)類型對(duì)象實(shí)現(xiàn)的。 8)func_weakreflist:弱引用列表 Python無(wú)法獲取這個(gè)屬性,,底層沒有提供相應(yīng)的接口,,關(guān)于弱引用此處就不深入討論了。 9)func_module:函數(shù)所在的模塊 def foo(name, age): pass
print(foo.__module__) # __main__
類,、方法,、協(xié)程也有 __module__ 屬性。
10)func_annotations:類型注解 def foo(name: str, age: int): pass
# Python3.5 新增的語(yǔ)法,,但只能用于函數(shù)參數(shù) # 而在 3.6 的時(shí)候,,聲明變量也可以使用這種方式 # 特別是當(dāng) IDE無(wú)法得知返回值類型時(shí),便可通過類型注解的方式告知 IDE # 這樣就又能使用 IDE 的智能提示了 print(foo.__annotations__) # {'name': <class 'str'>, 'age': <class 'int'>}
11)func_qualname:全限定名 def foo(): pass print(foo.__name__, foo.__qualname__) # foo foo
class A:
def foo(self): pass print(A.foo.__name__, A.foo.__qualname__) # foo A.foo
以上就是函數(shù)的底層結(jié)構(gòu),,在Python里面是由 function 實(shí)例化得到的,。 def foo(name, age): pass
# <class 'function'> 就是 C 里面的 PyFunction_Type print(foo.__class__) # <class 'function'>
但是這個(gè)類底層沒有暴露給我們,我們不能直接用,,因?yàn)楹瘮?shù)通過 def 創(chuàng)建即可,,不需要通過類型對(duì)象來(lái)創(chuàng)建。
后續(xù)會(huì)介紹更多關(guān)于相關(guān)的知識(shí),。
|