久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

《源碼探秘 CPython》56. 函數(shù)的底層結(jié)構(gòu)

 古明地覺O_o 2022-12-08 發(fā)布于北京

楔子


函數(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)的,,生得一副什么模樣。


PyFunctionObject


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__ 為 Noneprint(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) # 16print(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__) # numpyprint(np.ndarray.__name__) # ndarrayprint(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():    passprint(foo.__name__, foo.__qualname__)  # foo foo

class A:
def foo(self): passprint(A.foo.__name__, A.foo.__qualname__) # foo A.foo

小結(jié)


以上就是函數(shù)的底層結(jié)構(gòu),,在Python里面是由 function 實(shí)例化得到的,。

def foo(name, age):    pass
# <class 'function'> 就是 C 里面的 PyFunction_Typeprint(foo.__class__) # <class 'function'>

但是這個(gè)類底層沒有暴露給我們,我們不能直接用,,因?yàn)楹瘮?shù)通過 def 創(chuàng)建即可,,不需要通過類型對(duì)象來(lái)創(chuàng)建。

后續(xù)會(huì)介紹更多關(guān)于相關(guān)的知識(shí),。

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多