摘要:類元編程是指在運(yùn)行時(shí)創(chuàng)建或定制類的技藝。注意在中做元編程時(shí)最好不要用和函數(shù)。三元類基礎(chǔ)知識(shí)元類是類元編程最高級(jí)的工具使用元類可以創(chuàng)建具有某種特質(zhì)的全新變種,例如抽象基類。建議除非開發(fā)框架,否則不要在生產(chǎn)代碼中定義元類或抽象基類。
導(dǎo)語:本文章記錄了本人在學(xué)習(xí)Python基礎(chǔ)之元編程篇的重點(diǎn)知識(shí)及個(gè)人心得,打算入門Python的朋友們可以來一起學(xué)習(xí)并交流。本文重點(diǎn):
1、了解運(yùn)行時(shí)創(chuàng)建類的方法——類工廠函數(shù);
2、熟悉元類的基礎(chǔ)知識(shí)和使用場(chǎng)景;
3、了解元類的__prepare__的意義;
4、了解class的屬性以及Python解釋器如何處理導(dǎo)入的模塊。
類元編程是指在運(yùn)行時(shí)創(chuàng)建或定制類的技藝。
一、類工廠函數(shù)類是一等對(duì)象,因此任何時(shí)候都可以使用函數(shù)新建類,而無需使用class關(guān)鍵字。
實(shí)例: 下面我們寫一個(gè)簡(jiǎn)單的類工廠函數(shù):
def record_factory(cls_name,field_names): try: field_names=field_names.replace(","," ").split() except AttributeError: pass field_names=tuple(field_names)#使用屬性名構(gòu)建元組,這將成為新的__slots__。 def __init__(self,*args,**kwards):#通過字典解析輸入數(shù)據(jù),然后將值賦給新建的類的屬性。 attrs=dict(zip(self.__slots__,args)) attrs.update(kwards) for key,value in attrs.items(): setattr(self,key,value) def __iter__(self):#迭代特殊方法的思想在于讓解釋器查詢到屬性對(duì)應(yīng)的值。 for name in self.__slots__: yield getattr(self,name)#實(shí)現(xiàn)迭代的方法在于:通過內(nèi)置getattr方法獲取已經(jīng)初始化的類屬性對(duì)應(yīng)的值。 def __repr__(self):#返回一個(gè)合適的字符串。 msg=", ".join("{}={!r}".format(*i) for i in zip(self.__slots__,self)) return "{}({})".format(self.__class__.__name__,msg) cls_attrs=dict(__slots__=field_names, __init__=__init__, __iter__=__iter__, __repr__=__repr__) return type(cls_name,(object,),cls_attrs)#使用type構(gòu)造方法構(gòu)建新類并返回,注意object后的逗號(hào)很重要。 animal=record_factory("animal","name,age,price") dog=animal("dog","Bob","1000") print(dog)#構(gòu)造animal實(shí)例對(duì)象 a,b,_=dog#可以實(shí)現(xiàn)預(yù)期的拆包賦值 print(a,b)
輸出:
animal(name="dog", age="Bob", price="1000") dog Bob
type的三個(gè)參數(shù):class type(name, bases, dict)
type最后一個(gè)參數(shù)是一個(gè)映射,指定新類的屬性名和值。
注意:在Python中做元編程時(shí), 最好不要用 exec 和 eval 函數(shù).。如果接接收的字符串來自不可信的源,這兩個(gè)函數(shù)會(huì)帶來嚴(yán)重的安全風(fēng)險(xiǎn).
二、定制描述符的類裝飾器類裝飾器:本質(zhì)上是高階函數(shù),其參數(shù)是被裝飾的類,用于審查審查、修改、甚至把被裝飾的類替換成其他類。
類裝飾器的重大缺點(diǎn):只對(duì)直接依附的類有效。即被裝飾的類的子類可能繼承也可能不繼承裝飾器所做的改動(dòng),具體情況視改動(dòng)的方式而定。
三、元類 1、基礎(chǔ)知識(shí)元類:是類元編程最高級(jí)的工具:使用元類可以創(chuàng)建具有某種特質(zhì)的全新變種,例如抽象基類。
功能:元類是創(chuàng)建類的類。
特點(diǎn):
所有類都直接或間接地是type的實(shí)例,不過只有元類同時(shí)也是type的子類。
具體而言,元類可以通過實(shí)現(xiàn)__init__方法定制類。
為了避免無限回溯,type.__class是type,即type是自身的實(shí)例。
建議:除非開發(fā)框架,否則不要在生產(chǎn)代碼中定義元類或抽象基類。
實(shí)例:使用元類定制描述符
class EntityMeta(type): """Metaclass for business entities with validated fields""" def __init__(cls, name, bases, attr_dict): super().__init__(name, bases, attr_dict) # 創(chuàng)建類對(duì)象。 for key, attr in attr_dict.items(): # <2> if isinstance(attr, Validated): type_name = type(attr).__name__ attr.storage_name = "_{}#{}".format(type_name, key) class Entity(metaclass=EntityMeta): # <3> """Business entity with validated fields"""2、元類的使用場(chǎng)景:
驗(yàn)證屬性
一次把裝飾器依附到多個(gè)方法上
序列化對(duì)象或轉(zhuǎn)換數(shù)據(jù)
對(duì)象關(guān)系映射
基于對(duì)象的持久存儲(chǔ)
動(dòng)態(tài)轉(zhuǎn)換使用其他語言編寫為所有類定義的方法
四、元類的特殊方法__prepare____prepare__的功能:知道類的屬性定義的順序。
使用場(chǎng)景:__prepare__只在元類中有用,而且必須聲明為類方法(即要使用@classmethod 裝飾器定義)。
參數(shù)要求:__prepare__方法的第一個(gè)參數(shù)是元類,隨后兩個(gè)參數(shù)分別是要構(gòu)建的類的名稱和基類組成的元組, 返回值必須是映射。
工作原理:元類構(gòu)建新類時(shí),解釋器會(huì)先調(diào)用__prepare__ 方法,使用類定義體中的屬性創(chuàng)建映射。接著把__prepare__方法返回的映射會(huì)傳給__new__ 方法的最后一個(gè)參數(shù),然后再傳給__init__ 方法。
實(shí)例:使用__prepare__
class EntityMeta(type): """Metaclass for business entities with validated fields""" @classmethod def __prepare__(cls, name, bases): return collections.OrderedDict() # 返回一個(gè)空的 OrderedDict 實(shí)例,類屬性將存儲(chǔ)在里面。 def __init__(cls, name, bases, attr_dict): super().__init__(name, bases, attr_dict) cls._field_names = [] # 中創(chuàng)建一個(gè) _field_names 屬性 for key, attr in attr_dict.items(): if isinstance(attr, Validated): type_name = type(attr).__name__ attr.storage_name = "_{}#{}".format(type_name, key) cls._field_names.append(key) class Entity(metaclass=EntityMeta): """Business entity with validated fields""" @classmethod def field_names(cls): # field_names 類方法的作用簡(jiǎn)單:按照添加字段的順序產(chǎn)出字段的名稱 for name in cls._field_names: yield name五、其他 1、Python中的導(dǎo)入時(shí)和運(yùn)行時(shí)
在進(jìn)程中首次導(dǎo)入模塊時(shí),Python解釋器還會(huì)運(yùn)行所導(dǎo)入模塊中的全部頂層代碼。以后導(dǎo)入相同的模塊則使用緩存,只做名稱綁定。
對(duì)函數(shù)而言,首次導(dǎo)入模塊時(shí):解釋器會(huì)執(zhí)行頂層的 def 語句,編譯函數(shù)的定義體,把函數(shù)對(duì)象綁定到對(duì)應(yīng)的全局名稱上,但是顯然解釋器不會(huì)執(zhí)行函數(shù)的定義體。通常這意味著解釋器在導(dǎo)入時(shí)定義頂層函數(shù),但是僅當(dāng)在運(yùn)行時(shí)調(diào)用函數(shù)時(shí)才會(huì)執(zhí)行函數(shù)的定義體。
對(duì)類而言,首次導(dǎo)入模塊時(shí):解釋器會(huì)執(zhí)行每個(gè)類的定義體,甚至?xí)?zhí)行嵌套類的定義體。執(zhí)行類定義體的結(jié)果是,定義了類的屬性和方法,并構(gòu)建了類對(duì)象。從這個(gè)意義上理解,類的定義體屬于“頂層代碼”,因?yàn)樗趯?dǎo)入時(shí)運(yùn)行。
2、類的屬性class除了除__mro__、__class__、和__name__之外還有以下屬性:
cls.__bases__:由類的基類組成的元組。
cls.__qualname__:其值是類或函數(shù)的限定名稱,即從模塊的全局作用域到類的點(diǎn)分路徑。
cls.__subclasses__():這個(gè)方法返回一個(gè)列表,包含類的直接子類。其實(shí)現(xiàn)使用弱引用,防止超類和子類之間出現(xiàn)循環(huán)引用。這個(gè)方法返回的列表是內(nèi)存里現(xiàn)存的子類。
cls.mro():構(gòu)建類時(shí),如果需要獲取儲(chǔ)存在類屬性__mro__ 中的超類元組,解釋器會(huì)調(diào)用這個(gè)方法。元類可以覆蓋這個(gè)方法,定制要構(gòu)建的類解析方法的順序。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/41522.html
摘要:序言源起于開發(fā)者公眾號(hào)轉(zhuǎn)載的深刻理解中的元類一文回憶著自己看過的元編程一書參照寫個(gè)相應(yīng)的版和在很多方面都非常相像特別是的設(shè)計(jì)部分參考了但在很多方面它倆的很多概念并非一一對(duì)應(yīng)的在這里的元類在中并沒有相應(yīng)的概念如果理解為創(chuàng)建類的類最相近的應(yīng)該是 live with scope 序言 源起于Python開發(fā)者公眾號(hào)轉(zhuǎn)載的深刻理解Python中的元類一文, 回憶著自己看過的 Ruby元編程 一...
摘要:先簡(jiǎn)單介紹下中的元類。元類就是創(chuàng)建類的類,對(duì)于元類來說,類是它的實(shí)例,將返回。中的所有類,都是的實(shí)例,換句話說,是元類的基類。 我在看源代碼的時(shí)候,經(jīng)常蹦出這一句:How does it work!竟然有這種操作?本系列文章,試圖剖析代碼中發(fā)生的魔法。順便作為自己的閱讀筆記,以作提高。 先簡(jiǎn)單介紹下Python中的元類(metaclass)。元類就是創(chuàng)建類的類,對(duì)于元類來說,類是它的實(shí)...
摘要:如果還是沒有找到,就會(huì)使用父類中的元類來創(chuàng)建類。元類通常用于處理比較復(fù)雜的情況。這是因?yàn)槭褂昧嗽?,它?huì)將中定義的字段轉(zhuǎn)換成數(shù)據(jù)庫中的字段。中所有數(shù)據(jù)類型都是對(duì)象,它們要么是類的實(shí)例要么是元類的實(shí)例。 原文地址:what is metaclass in Python?我的簡(jiǎn)書地址::nummy 類即對(duì)象 在理解元類之前,需要先掌握Python中的類,Python中類的概念與SmallT...
摘要:而導(dǎo)致這個(gè)問題的原因是線程并行執(zhí)行操作并不是原子的,存在線程安全問題。如果已經(jīng)有線程持有了鎖,那這個(gè)線程會(huì)獨(dú)占鎖,直到鎖釋放完畢之前,其他線程都會(huì)被阻塞。當(dāng)鎖處于重量級(jí)鎖狀態(tài),其他線程嘗試獲取鎖時(shí),都會(huì)被阻塞,也就是狀態(tài)。 1. 什么時(shí)候需要用SynchronizedSynchronized主要作用是在多個(gè)線程操作共享數(shù)據(jù)的時(shí)候,保證對(duì)共享數(shù)據(jù)訪問的線程安全性。比如兩個(gè)線程對(duì)于i這個(gè)共...
摘要:導(dǎo)語本文章匯總了本人在學(xué)習(xí)基礎(chǔ)之緒論篇數(shù)據(jù)結(jié)構(gòu)篇函數(shù)篇面向?qū)ο笃刂屏鞒唐驮幊唐獙W(xué)習(xí)筆記的鏈接,打算入門的朋友們可以按需查看并交流。 導(dǎo)語:本文章匯總了本人在學(xué)習(xí)Python基礎(chǔ)之緒論篇、數(shù)據(jù)結(jié)構(gòu)篇、函數(shù)篇、面向?qū)ο笃⒖刂屏鞒唐驮幊唐獙W(xué)習(xí)筆記的鏈接,打算入門Python的朋友們可以按需查看并交流。 第一部分:緒論篇 1、Python數(shù)據(jù)模型 第二部分:數(shù)據(jù)結(jié)構(gòu)篇 2、序列構(gòu)成...
閱讀 669·2021-11-22 15:32
閱讀 2761·2021-11-19 09:40
閱讀 2378·2021-11-17 09:33
閱讀 1327·2021-11-15 11:36
閱讀 1916·2021-10-11 10:59
閱讀 1522·2019-08-29 16:41
閱讀 1824·2019-08-29 13:45
閱讀 2207·2019-08-26 13:36