實(shí)現(xiàn)python?namedtuple元類編程
起步
namedtuple
是 collections
模塊下的一個功能,它是類工廠函數(shù),能返回 tuple
子類,允許通過字段名向元組中取值,性能上接近于元組。
Person = namedtuple('Person', 'name age') p = Person(name='Tony', age=18) print(p.name) # 'Tony' print(p.age) # 18
我們來試著自己動手來實(shí)現(xiàn)這個 namedtuple
功能。因?yàn)檫@個功能需求明確,沒什么模塊依賴,通過自己的實(shí)現(xiàn)后再去看看真正在 cpython
里的源碼就會比較清晰。
需求分析
對于代碼 Person = namedtuple('Person', 'name age')
讓它等價于:
class Person(tuple): def __new__(cls, name, age): return tuple.__new__(cls, (name, age)) @property def name(self): return self[0] @property def age(self): return self[1]
那么有一種實(shí)現(xiàn)就是,拼湊成這樣的代碼塊字符串,再通過 exec(code)
來創(chuàng)建類,舊版本(小于 3.7
)的 namedtuple
在 cpython 中還真就是這么實(shí)現(xiàn)的。
PS: 重寫了 __new__
而不是 __init__
,有一個原因是因?yàn)樵M一旦創(chuàng)建就不可變。為了能夠通過字段名取值,這里引入了 property
修飾符。
構(gòu)造類的字符串模板創(chuàng)建類
基于這個思路一個簡陋的就能寫了出來:
# 類名稱模板 _class_template = ''' class {typename}(tuple): def __new__(_cls, {arg_list}): return tuple.__new__(_cls, ({arg_list})) {field_defs} ''' # 屬性模板 _field_template = ''' @property def {name}(self): return self[{index}] ''' def namedtuple(typename, field_names): field_names = field_names.split() class_definition = _class_template.format( typename=typename, arg_list=arg_list = repr(field_names).replace("'", "")[1:-1], field_defs=''.join(_field_template.format(index=index, name=name) for index, name in enumerate(field_names)) ) namespace = {} exec(class_definition, namespace) return namespace[typename] # use demo Person = namedtuple('Person', 'name age') p = Person(name='Tony', age=18) print(isinstance(p, tuple)) # True print(p.name) # Tony print(p.age) # 18
cpython
中的 namedtuple
便是基于這個思路實(shí)現(xiàn)的
源碼:https://github.com/python/cpy...,這個實(shí)現(xiàn)方式一直沿用到了 3.6.x 。
直到因?yàn)樾阅茉蚨M(jìn)行了改版,PR見:https://github.com/python/cpy...
基于元類編程
改進(jìn)后的 namedtuple
更能體現(xiàn)元類編程的思想,對性能也有明顯的改善。我用簡化的代碼來展示改版后的 namedtuple
的工作內(nèi)容:
def _tuplegetter(index): @property def _getter(self): return self[index] return _getter def namedtuple(typename, field_names): field_names = field_names.split() arg_list = repr(field_names).replace("'", "")[1:-1] s = f'def __new__(_cls, {arg_list}): return tuple.__new__(_cls, ({arg_list}))' namespace = {} exec(s, namespace) __new__ = namespace['__new__'] class_namespace = {'__new__': __new__} for index, name in enumerate(field_names): class_namespace[name] = _tuplegetter(index) result = type(typename, (tuple,), class_namespace) return result
到此,一個簡易版的 namedtuple
就結(jié)構(gòu)就完成了,改進(jìn)后的 exec
調(diào)用中只有一行代碼,性能會更好,舊版本的還會額外 import 其他依賴。然后就是構(gòu)造元類編程中類屬性和方法了。屬性的獲取是通過寫的 _getter
來完成,而實(shí)際上源碼上會委托給 operator.itemgetter
函數(shù)。
總結(jié)
相信從本文中理解了 namedtuple
的設(shè)計(jì)和實(shí)現(xiàn)原理,再去閱讀源代碼,能更快的理解源碼,起到事半功倍的效果。
以上就是實(shí)現(xiàn)python namedtuple元類編程的詳細(xì)內(nèi)容,更多關(guān)于python namedtuple元類的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python如何在for循環(huán)中同時使用兩個變量與兩個控制條件
Python是一種廣泛使用的編程語言,其提供了許多強(qiáng)大的方法來處理代碼,Python?for循環(huán)是其中一種非常有用的方法,下面這篇文章主要給大家介紹了關(guān)于Python如何在for循環(huán)中同時使用兩個變量與兩個控制條件的相關(guān)資料,需要的朋友可以參考下2024-03-03Python Opencv實(shí)現(xiàn)最強(qiáng)美顏濾鏡效果
這篇文章主要介紹了如何利用Python OpenCV制作一個強(qiáng)大的美顏濾鏡效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以學(xué)習(xí)一下2022-03-03pytorch torch.expand和torch.repeat的區(qū)別詳解
這篇文章主要介紹了pytorch torch.expand和torch.repeat的區(qū)別詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11人工智能學(xué)習(xí)Pytorch教程Tensor基本操作示例詳解
這篇文章主要為大家介紹了人工智能學(xué)習(xí)Pytorch教程Tensor的基本操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-11-11如何利用Python處理excel表格中的數(shù)據(jù)
Excel做為職場人最常用的辦公軟件,具有方便、快速、批量處理數(shù)據(jù)的特點(diǎn),下面這篇文章主要給大家介紹了關(guān)于如何利用Python處理excel表格中數(shù)據(jù)的相關(guān)資料,需要的朋友可以參考下2022-03-03Python+Flask實(shí)現(xiàn)自定義分頁的示例代碼
分頁操作在web開發(fā)中幾乎是必不可少的,而flask不像django自帶封裝好的分頁操作。所以本文將自定義實(shí)現(xiàn)分頁效果,需要的可以參考一下2022-09-09