Python 類與元類的深度挖掘 II【經(jīng)驗(yàn)】
上一篇解決了通過調(diào)用類對象生成實(shí)例對象過程中可能遇到的命名空間相關(guān)的一些問題,這次我們向上回溯一層,看看類對象本身是如何產(chǎn)生的。
我們知道 type() 方法可以查看一個(gè)對象的類型,或者說判斷這個(gè)對象是由那個(gè)類產(chǎn)生的:
print(type(12))
print(type('python'))
class A:
pass
print(type(A))
通過這段代碼可以看出,類對象 A 是由type() 產(chǎn)生的,也就是說 type 也可以用來產(chǎn)生新的對象,而且產(chǎn)生的是類對象,因此它是所有類對象的類:
print(type.__doc__) type(object_or_name, bases, dict) type(object) -> the object's type type(name, bases, dict) -> a new type
class 定義類的語法實(shí)際上轉(zhuǎn)化為 type(name, bases, dict),其中 name 參數(shù)為類的名字,bases 為繼承父類的元組,dict 為類的屬性和方法:
class A:
pass
# 實(shí)際上等于
B = type('A', (), {})
print(A.__name__ == B.__name__)
True
理論上說這就是元類的意義,但從實(shí)際的角度出發(fā)顯然使用 class 語法更方便、合理,而元類的實(shí)際意義則是通過繼承 type 類來構(gòu)造一個(gè)新的元類,并進(jìn)行特定的操作以產(chǎn)生具有特定行為的類對象。這樣看來它的本質(zhì)與普通的類對象沒有差異,只不過繼承的是 type 類。
在生成實(shí)例時(shí)是通過調(diào)用 __init__ 方法進(jìn)行初始化的,而實(shí)際上在此之前會先調(diào)用 __new__ 方法用于創(chuàng)建實(shí)例,再通過 __init__ 初始化,就好像 __new__ 負(fù)責(zé)聲明變量,而 __init__ 負(fù)責(zé)對聲明的變量進(jìn)行初始化一樣。這里有一個(gè)規(guī)則是 __new__(cls,) 的返回值必須是 cls 參數(shù)的實(shí)例,否則 __init__ 將不會觸發(fā),例如在 enum.Enum 的定義中,由于枚舉類型是單例模式,因此在定義 __new__ 的時(shí)候沒有返回其實(shí)例,也就不會進(jìn)行初始化:
class Enum:
def __new__(cls, value):
print(cls, value)
return value
def __init__(self):
print("Will not be called!")
e = Enum(1)
<class '__main__.Enum'> 1
通常情況下自己定義 __new__ 需要通過調(diào)用父類的 __new__ 方法創(chuàng)建一個(gè) cls 的實(shí)例,同樣在定義元類的時(shí)候則是調(diào)用上面提到的 type 的用法(因?yàn)樵惱^承自 type):
class MetaEnum(type):
def __new__(metaclass, name, base, attrs):
print("Metaclass: {}\nName: {}\nParents: {}\nAttributes: {}".format(metaclass, name, base, attrs))
return super().__new__(metaclass, name, base, attrs)
class Enum(metaclass=MetaEnum):
# Python 2.7 中定義元類的方法是使用 __metaclass__ 變量
# [PEP 3115](https://www.python.org/dev/peps/pep-3115/)
# 將 Python 3.0 以后語法改為 class Cls(metaclass=Meta)
test = 0
Metaclass:
Name: Enum
Parents: ()
Attributes: {'__qualname__': 'Enum', '__module__': '__main__', 'test': 0}
此時(shí)我們再來看 Enum 的類,已經(jīng)不再是 type 而是其元類 MetaEnum:
type(Enum)
__main__.MetaEnum
除了 __new__ 方法之外,PEP 3115 還定義了 __prepare__ 屬性,用于設(shè)定初始化的命名空間(即 type 的第 3 個(gè)參數(shù)),還是以 enum.Enum 為例,我們需要限制枚舉類型中屬性名稱不得重復(fù)使用,則可以通過元類限制類的行為:
# 定義新的字典類,在賦值新的 dict[k] = v 時(shí)
# 檢查 k 是否重復(fù)
class _EnumDict(dict):
def __init__(self):
super().__init__()
self.members = []
def __setitem__(self, k, v):
if k in self.members:
raise TypeError("Attempted to reuse key: '{}'".format(k))
else:
self.members.append(k)
super().__setitem__(k, v)
class MetaEnum(type):
@classmethod
def __prepare__(metaclass, cls, bases):
return _EnumDict()
def __new__(metaclass, name, base, attrs):
return super().__new__(metaclass, name, base, attrs)
class Enum(metaclass=MetaEnum):
pass
class Color(Enum):
try:
red = 1
red = 2
except TypeError:# 這里沒有使用 as err: 的原因是?
print("TypeError catched")
TypeError catched
Python 中一切皆為對象,所有的對象都是某一類的實(shí)例,或是某一元類的實(shí)例,type 是自己的元類也是自己的實(shí)例
- Python基礎(chǔ)之元類詳解
- Python自定義元類的實(shí)例講解
- 詳解python metaclass(元類)
- Python如何定義有可選參數(shù)的元類
- Python 使用元類type創(chuàng)建類對象常見應(yīng)用詳解
- 深入了解python中元類的相關(guān)知識
- Python 元類實(shí)例解析
- 舉例講解Python中metaclass元類的創(chuàng)建與使用
- Python 類與元類的深度挖掘 I【經(jīng)驗(yàn)】
- 在Python中使用元類的教程
- Python中的元類編程入門指引
- 深入理解Python中的元類(metaclass)
- python中元類用法實(shí)例
- Python 元類使用說明
- Python進(jìn)階學(xué)習(xí)之帶你探尋Python類的鼻祖-元類
相關(guān)文章
matplotlib之pyplot模塊坐標(biāo)軸范圍設(shè)置(autoscale(),xlim(),ylim())
這篇文章主要介紹了matplotlib之pyplot模塊坐標(biāo)軸范圍設(shè)置(autoscale(),xlim(),ylim()),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
Python使用missingno模塊輕松處理數(shù)據(jù)缺失
missingno是一個(gè)基于Python的開源數(shù)據(jù)可視化工具,旨在幫助數(shù)據(jù)分析師和科學(xué)家更好地理解和處理數(shù)據(jù)缺失,下面我們就來看看如何使用missingno處理數(shù)據(jù)缺失吧2024-02-02
使用python測試prometheus的實(shí)現(xiàn)
本文主要介紹了使用python測試prometheus的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02
Python Collections強(qiáng)大的數(shù)據(jù)結(jié)構(gòu)工具使用實(shí)例探索
這篇文章主要介紹了Python Collections強(qiáng)大的數(shù)據(jù)結(jié)構(gòu)工具的使用實(shí)例探索,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01
Python調(diào)用C語言的方法【基于ctypes模塊】
這篇文章主要介紹了Python調(diào)用C語言的方法,涉及Python基于ctypes模塊調(diào)用C語言編譯后的動態(tài)鏈接庫文件相關(guān)操作技巧,需要的朋友可以參考下2018-01-01
python獲取文件真實(shí)鏈接的方法,針對于302返回碼
今天小編就為大家分享一篇python獲取文件真實(shí)鏈接的方法,針對于302返回碼,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-05-05

