3. 自定义元类
在 Python 语言中,用户可以自己定义元类,用户自定义的元类必须直接或间接的继承自 type 类。
作用
自定义元类通常用于控制此元类创建类的行为。实现自定义的功能。
语法
class 新元类(基础元类):
...
如:
class MyMetaClass(type):
pass
说明
自定义元类的 可以通过覆盖 type 类的 __new__
和 __init__
方法来控制类在创建过程中的行为。
使用元类来创建新类
语法
class 新类(基类1, 基类2, ..., metaclass=元类):
...
如:
class Animal(object, metaclass=MyMetaClass):
home = '地球'
def print_home(self):
print(self.__class__.home)
说明
- 如果一类个默认没有指定 metaclass,则这个类直接由 type 类来创建。
- 如果一类指定了 metaclass,则这个类直接由 metaclass 指定的类来创建。
- 因为元类都直接或间接的继承自 type 类,因此所有用自定义元类创建的新类都要调用
type.__new__(cls, name, bases, namespace)
来创建新类,即使用type函数来创建类。
元类的 __new__
和 __init__
方法
- 元类的
__new__
方法在类定义时执行,用于创建类并指定类属性和方法等。 - 元类的
__init__
方法在新类创建后执行,用来初始化类。但魏老师没有用到过这个方法,不常用。
示例
自定义元类 MyMetaClass,此类继承自 type。
class MyMetaClass(type):
pass
用 MyMetaClass 创建一个新类 Animal,此类继承自object,用元类 MyMetaClass 创建。
class Animal(object, metaclass=MyMetaClass):
pass
测试打印 创建 Animal 的类和 MyMetaClass 的类都是什么?
print('创建Animal类的类是:', Animal.__class__)
print('创建MyMetaClass类的类是:', MyMetaClass.__class__)
运行结果
创建Animal类的类是: <class '__main__.MyMetaClass'>
创建MyMetaClass类的类是: <class 'type'>
改写MyMetaClass 添加 __new__
和 __init__
方法。并打印传入的参数。如下:
class MyMetaClass(type):
def __new__(cls, name, bases, namespace):
print('MyMetaClass.__new__: name:', name, 'bases:', bases, 'namespace', namespace)
return super().__new__(cls, name, bases, namespace)
def __init__(self, name, bases, namespace):
print('MyMetaClass.__init__: name:', name, 'bases:', bases, 'namespace', namespace)
super().__init__(name, bases, namespace)
class Animal(object, metaclass=MyMetaClass):
pass
运行结果如下:
MyMetaClass.__new__: name: Animal bases: (<class 'object'>,) namespace {'__module__': '__main__', '__qualname__': 'Animal', '__firstlineno__': 15, '__static_attributes__': ()}
MyMetaClass.__init__: name: Animal bases: (<class 'object'>,) namespace {'__module__': '__main__', '__qualname__': 'Animal', '__firstlineno__': 15, '__static_attributes__': ()}
可见,在创建类 Animal 时 调用了 __new__
和 __init__
方法。并传入了类 Animal的名称、继承元组和属性信息。
修改 Animal 类如下,添加了两个类属性。继续运行程序
class Animal(object, metaclass=MyMetaClass):
home = '地球'
def print_home(self):
print(self.__class__.home)
运行结果如下:
MyMetaClass.__new__: name: Animal bases: (<class 'object'>,) namespace {'__module__': '__main__', '__qualname__': 'Animal', '__firstlineno__': 15, 'home': '地球', 'print_home': <function Animal.print_home at 0x1091c45e0>, '__static_attributes__': ()}
MyMetaClass.__init__: name: Animal bases: (<class 'object'>,) namespace {'__module__': '__main__', '__qualname__': 'Animal', '__firstlineno__': 15, 'home': '地球', 'print_home': <function Animal.print_home at 0x1091c45e0>, '__static_attributes__': ()}
可见 Animal 类中的两个类属性也会以键值对的形式传递给元类 的 __new__
和 __init__
的 第四个参数 namespace。
最后再创建一个Animal类的子类,在创建此类时依旧会调用元类 MyMetaClass 中的 __new__
和 __init__
方法。代码如下
class MyMetaClass(type):
def __new__(cls, name, bases, namespace):
print('MyMetaClass.__new__: name:', name, 'bases:', bases, 'namespace', namespace)
return super().__new__(cls, name, bases, namespace)
def __init__(self, name, bases, namespace):
print('MyMetaClass.__init__: name:', name, 'bases:', bases, 'namespace', namespace)
super().__init__(name, bases, namespace)
class Animal(object, metaclass=MyMetaClass):
home = '地球'
def print_home(self):
print(self.__class__.home)
class Dog(Animal):
pass
print('创建Animal类的类是:', Animal.__class__)
print('创建MyMetaClass类的类是:', MyMetaClass.__class__)
运行结果
MyMetaClass.__new__: name: Animal bases: (<class 'object'>,) namespace {'__module__': '__main__', '__qualname__': 'Animal', '__firstlineno__': 15, 'home': '地球', 'print_home': <function Animal.print_home at 0x1091c45e0>, '__static_attributes__': ()}
MyMetaClass.__init__: name: Animal bases: (<class 'object'>,) namespace {'__module__': '__main__', '__qualname__': 'Animal', '__firstlineno__': 15, 'home': '地球', 'print_home': <function Animal.print_home at 0x1091c45e0>, '__static_attributes__': ()}
MyMetaClass.__new__: name: Dog bases: (<class '__main__.Animal'>,) namespace {'__module__': '__main__', '__qualname__': 'Dog', '__firstlineno__': 21, '__static_attributes__': ()}
MyMetaClass.__init__: name: Dog bases: (<class '__main__.Animal'>,) namespace {'__module__': '__main__', '__qualname__': 'Dog', '__firstlineno__': 21, '__static_attributes__': ()}
创建Animal类的类是: <class '__main__.MyMetaClass'>
创建MyMetaClass类的类是: <class 'type'>