python元类MetaClass用法教程

__new__ 方法也用于自定义元类(MetaClass),下面先来介绍MetaClass的概念。

1.什么是MetaClass

metaclass定义为类中的类(the class of a class),Meta 起源于希腊词汇 meta,有“超越”和“改变”的意思,所以metaclass包含了“超越类”和“变形类”的含义。

先来看一个例子:

>>> class MyClass(object): data = 6
...
>>> myobject = MyClass()
>>> print(myobject.__class__)
<class '__main__.MyClass'>
>>> print(MyClass.__class__)
<class 'type'>
>>>

上面的例子中,myobject对象的类为MyClass,MyClass的类是type,也就是说myobject是一个MyClass对象,而MyClass又是一个type对象。

type就是一个元类,它是最常用的元类,是Python中所有类的默认元类,所有的 Python 的用户定义类,都是 type 这个类的实例。

元类被用来构造类(就像类用来构造对象一样)。Python类的创建过程如下:

进行类定义时,Python收集属性到一个字典中
类定义完成后,确定类的元类Meta,执行Meta(name, bases, dct)进行实例化。

  • Meta是元类
  • name:类的名称,__name__属性
  • bases:类的基类元组,__bases__属性
  • dct:将属性名映射到对象中,列出类的所有属性,__dict__属性

可以使用type直接创建类:

>>> myobject = type('MyClass', (), {
    
    'data': 6})
>>> print(myobject.__class__)
<class 'type'>

>>> print(myobject.__name__)
MyClass
>>> print(myobject.__bases__)
(<class 'object'>,)
>>> print(myobject.data)
6
>>> print(myobject.__dict__)
{
    
    'data': 6, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'MyClass' objects>, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__doc__': None}

也就是说当定义MyClass类时,真正执行的是:class = type(name, bases, dct) 语句,

如果一个类或它的一个基类有__metaclass__属性,它就被当作元类。否则,type就是元类。对元类的自定义要用到__new__ 和 __init__方法,接下来介绍元类的定义。

2.定义元类

元类可以实现在创建类时,动态修改类中定义的属性或者方法,一般使用__new__方法来修改类属性。

下面的例子使用元类来添加属性方法:

class MyMetaClass(type):
    def __new__(meta, name, bases, attrs):
        print(meta, "__new__ is called")
        # 动态添加属性
        attrs['name'] = "zhangsan"
        attrs['talk'] = lambda self: print("hello")
        return super(MyMetaClass, meta).__new__(meta, name, bases, attrs)

    @classmethod
    def __prepare__(metacls, name, bases, **kwargs):
        print(metacls, "__prepare__ is called")
        return super().__prepare__(name, bases, **kwargs)

    def __init__(cls, name, bases, attrs, **kwargs):
        print(cls, "__init__ is called")
        super().__init__(name, bases, attrs)

    def __call__(cls, *args, **kwargs):
        print(cls, "__call__ is called")
        return super().__call__(*args, **kwargs)


class Myclass(metaclass=MyMetaClass):
    pass

#学习中遇到问题没人解答?小编创建了一个Python学习交流群:725638078
if __name__ == '__main__':
    cla = Myclass()
    print(cla.name)
    cla.talk()
    print(cla.__dir__())

执行结果:

<class '__main__.MyMetaClass'> __prepare__ is called
<class '__main__.MyMetaClass'> __new__ is called
<class '__main__.Myclass'> __init__ is called
<class '__main__.Myclass'> __call__ is called
zhangsan
hello
['__module__', 'name', 'talk', '__dict__', '__weakref__', '__doc__', '__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__init__', '__new__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']

可以看到元类MyMetaClass的__new__()方法动态地为 Myclass 类添加了 name 属性和 talk() 方法。

在元类的创建中,可以对name, bases, attrs进行修改,实现我们想要的功能,可以使用getattr()、setattr()等Python反射函数

猜你喜欢

转载自blog.csdn.net/qdPython/article/details/129816163