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