type() 函數(shù)更適合于動態(tài)地創(chuàng)建相對簡單的類,如果要創(chuàng)建更復(fù)雜的類,則需要通過 MetaClass(元類)的方式。
MetaClass(元類),簡單的理解,就是創(chuàng)建類的類,即創(chuàng)建類之后,再由類來創(chuàng)建實(shí)例進(jìn)行應(yīng)用。使用元類可以在創(chuàng)建類時動態(tài)修改類定義。為了使用元類動態(tài)修改類定義,程序需要先定義元類。
定義元類時,需令其繼承與 type 類,且默認(rèn)的命名習(xí)慣是,讓類名以 MetaClass 結(jié)尾。不僅如此,元類中需要定義并實(shí)現(xiàn) __new__() 方法(一定要有返回值)。因?yàn)樵愒趧?chuàng)建類時,該 __new__() 方法將會被調(diào)用,用來生成新建的類。
之所有要求元類繼承 type 并實(shí)現(xiàn) __new__() 方法,是因?yàn)樵趧?chuàng)建類時,內(nèi)部調(diào)用了 type 的 __new__() 方法為這個類分配內(nèi)存空間,當(dāng)內(nèi)存分配完成后,便會調(diào)用 type 的 _init__ 方法初始化。 下面程序定義了一個元類類:# 定義Item元類,繼承type class ItemMetaClass(type): # cls代表動態(tài)修改的類 # name代表動態(tài)修改的類名 # bases代表被動態(tài)修改的類的所有父類 # attr代表被動態(tài)修改的類的所有屬性、方法組成的字典 def __new__(cls, name, bases, attrs): # 動態(tài)為該類添加一個cal_price方法 attrs['cal_price'] = lambda self: self.price * self.discount return type.__new__(cls, name, bases, attrs)
上面程序定義了一個 ItemMetaClass,該類繼承了 type 類,并重寫了 __new__ 方法,在重寫該方法時為目標(biāo)類動態(tài)添加了一個 cal_price 方法。元類的 __new__ 方法的作用是:當(dāng)程序使用 class 定義新類時,如果指定了元類,那么元類的 __new__ 方法就會被自動執(zhí)行。 例如,如下程序使用元類定義了兩個類:# 定義Book類 class Book(metaclass=ItemMetaClass): __slots__ = ('name', 'price', '_discount') def __init__(self, name, price): self.name = name self.price = price @property def discount(self): return self._discount @discount.setter def discount(self, discount): self._discount = discount # 定義cellPhone類 class CellPhone(metaclass=ItemMetaClass): __slots__ = ('price', '_discount' ) def __init__(self, price): self.price = price @property def discount(self): return self._discount @discount.setter def discount(self, discount): self._discount = discount
上面程序定義了 Book 和 CellPhone 兩個類,在定義這兩個類時都指定了元類信息,因此當(dāng) Python 解釋器在創(chuàng)建這兩個類時,ItemMetaClass 的 __new__ 方法就會被調(diào)用,用于修改這兩個類。
ItemMetaClass 類的 __new__ 方法會為目標(biāo)類動態(tài)添加 cal_price 方法,因此,雖然在定義 Book、CellPhone 類時沒有定義 cal_price() 方法,但這兩個類依然有 cal_price() 方法。如下程序測試了 Book、CellPhone 兩個類的 cal_price() 方法:
b = Book("Python基礎(chǔ)教程", 89) b.discount = 0.76 # 創(chuàng)建Book對象的cal_price()方法 print(b.cal_price()) cp = CellPhone(2399) cp.discount = 0.85 # 創(chuàng)建CellPhone對象的cal_price()方法 print(cp.cal_price())
運(yùn)行上面程序,可以看到如下運(yùn)行結(jié)果:67.64 2039.1499999999999 從上面的運(yùn)行結(jié)果來看,通過使用元類可以動態(tài)修改程序中的一批類,對它們集中進(jìn)行某種修改。這個功能在開發(fā)一些基礎(chǔ)性框架時非常有用,程序可以通過使用元類為某一批需要具有通用功能的類添加方法。
|