python3 之metaclass


如果希望創建某一批類全部具有某種特征,則可通過 metaclass 來實現。使用 metaclass 可以在創建類時動態修改類定義。

為了使用 metaclass 動態修改類定義,程序需要先定義 metaclass, metaclass 應該繼承 type 類,並重寫 __new__() 方法。

下面程序定義了一個 metaclass 類:

#定義ItemMetaClass,繼承type
class ItemMetaClass(type):
    # cls 代表動態修改的類
    # name 代表動態修改的類名
    # bases 代表被動態修改的類的所有父類
    # attrs 代表被動態修改的類的所有屬性、方法組成的字典

    def __new__(cls, name, bases, attrs):
        #動態為該類添加一個cal_price方法
        attrs['cal_price'] = lambda self:self.price * self._discount
        return type.__new__(cls, name, bases, attrs)

上面程序定義了一個 ItemMetaClass 類,該類繼承了 type 類,並重寫了 __new__ 方法,在重寫該方法時為目標類動態添加了一個 cal_price 方法。

metaclass 類的 __new__ 方法的作用是:當程序使用 class 定義新類時,如果指定了 metaclass,那么 metaclass 的 __new__ 方法就會被自動執行。

例如,如下程序使用 metaclass 定義了兩個類:

#定義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 兩個類,在定義這兩個類時都指定了 metaclass 信息,因此當 Python 解釋器在創建這兩個類時,ItemMetaClass 的 __new__ 方法就會被調用,用於修改這兩個類。

ItemMetaClass 類的 __new__ 方法會為目標類動態添加 cal_price 方法,因此,雖然在定義 Book、CellPhone 類時沒有定義 cal_price() 方法,但這兩個類依然有 cal_price() 方法。如下程序測試了 Book、CellPhone 兩個類的 cal_price() 方法: 

#Book類實例化
b = Book('Python基礎教程', 89)
b.discount = 0.8
#Book類的cal_price()方法
print(b.cal_price())

#CellPhone類實例化
cp = CellPhone(2300)
cp.discount = 0.85
#CellPhone類的cel_price方法
print(cp.cal_price())

  

輸出結果如下:

71.2
1955.0

  

 

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM