每當我們定義新類別的時候,元類別就會運行雅正程式碼,以確保這個新類別符合規定的規格。
Python系統把子類別的class語句處理完畢,就會呼叫元類別的 __new__
方法。元類別可以透過 __new__
方法,取得子類別、孫子類別的名稱,父親及屬性。
這樣使得我們不需要將驗證程式碼放在本類別 __init__
方法中,等到建置物件再驗證。
下例中,定義一個邊數小於3的子類,class語句一結束,元類的驗證程式碼就會拒絕這個class。
class ValidatePolygon(type): def __new__(meta, name, bases, class_dict): # Don't validate the abstract Polygon class if bases != (object,): if class_dict['sides'] < 3: raise ValueError('Polygons need 3+ sides') return type.__new__(meta, name, bases, class_dict) class Polygon(object, metaclass=ValidatePolygon): sides = None # Specified by subclasses @classmethod def interior_angles(cls): return (cls.sides - 2) * 180 class Triangle(Polygon): sides = 3 print(Triangle.interior_angles())
每次從基底類別繼承子類別時,基底類別的元類別都可以自動執行註冊代碼。
這在需要反向查找 ‘reverse lookup’ 時很有用,使得在簡單標識符和對應的類別之間,建立映射關係。
依然利用的是class語句執行完,自動呼叫元類別的 __new__
方法。
import json registry = {} def register_class(target_class): registry[target_class.__name__] = target_class def deserialize(data): params = json.loads(data) name = params['class'] target_class = registry[name] return target_class(*params['args']) class Meta(type): def __new__(meta, name, bases, class_dict): cls = type.__new__(meta, name, bases, class_dict) register_class(cls) return cls class Serializable(object): def __init__(self, *args): self.args = args def serialize(self): return json.dumps({ 'class': self.__class__.__name__, 'args': self.args, }) def __repr__(self): return '%s(%s)' % ( self.__class__.__name__, ', '.join(str(x) for x in self.args)) class RegisteredSerializable(Serializable, metaclass=Meta): pass class Vector3D(RegisteredSerializable): def __init__(self, x, y, z): super().__init__(x, y, z) self.x, self.y, self.z = x, y, z v3 = Vector3D(10, -7, 3) print('Before: ', v3) data = v3.serialize() print('Serialized:', data) print('After: ', deserialize(data)) print(registry)
使用元類別像是在 class 語句上放置了掛鉤,class語句處理完畢,掛鉤就會立刻觸發。
下列中藉助元類別設定了 Filed.name
和 Filed.name
。
class Field(object): def __init__(self): # These will be assigned by the metaclass. self.name = None self.internal_name = None def __get__(self, instance, instance_type): if instance is None: return self return getattr(instance, self.internal_name, '') def __set__(self, instance, value): setattr(instance, self.internal_name, value) class Meta(type): def __new__(meta, name, bases, class_dict): for key, value in class_dict.items(): if isinstance(value, Field): value.name = key value.internal_name = '_' + key cls = type.__new__(meta, name, bases, class_dict) return cls class DatabaseRow(object, metaclass=Meta): pass class BetterCustomer(DatabaseRow): first_name = Field() last_name = Field() prefix = Field() suffix = Field() foo = BetterCustomer() print('Before:', repr(foo.first_name), foo.__dict__) foo.first_name = 'Euler' print('After: ', repr(foo.first_name), foo.__dict__)
元類別總結就到這裡,自己也沒有完全理解清楚。
希望對此有深刻理解的pythoner留言。
程式碼來自:
以上是詳細講解Python中的元類別及其用法的詳細內容。更多資訊請關注PHP中文網其他相關文章!