暗无天日

=============>DarkSun的个人博客

python3中的元类

元类(metaclass)

Python元编程依赖于一种特别的类,叫做元类(metaclass). 根据 Wikipedia 的说法: "面向对象中的元类就是实例为类的类"

metaclass可以为新类定义属性,比如,下面这个名为 HelloMeta 的元类,可以为每个使用该元类为模板的类添加一个 hello 属性,而无需这些类自己定义:

class HelloMeta(type):
    # 定义一个 hello 方法
    def hello(cls):
        print("greetings from %s, a HelloMeta type class" % (type(cls())))

    # 调用该metaclass的方法
    def __call__(self, *args, **kwargs):
        # 正常创建新类
        cls = type.__call__(self, *args, **kwargs)

        # 但是为每个创建的类添加一个hello方法
        setattr(cls, "hello", self.hello)

        # print('__call__() from HelloMeta',args,kwargs)
        # 返回这个新建的类
        return cls

class TryHello(object, metaclass=HelloMeta):
    def greet(self):
        self.hello()

# TryHello.hello()
greeter = TryHello()
greeter.hello()

结果为:

greetings from <class '__main__.TryHello'>, a HelloMeta type class

你可以看到,虽然 TryHello 本身没有定义 hello 函数,但是由于使用了 HelloMeta 元类,因此也有了 hello 方法

也就是说,元类能给我们带来修改代码本身的能力,因此被大量应用于框架中

Metaclass的工作原理

在了解Metaclass的工作原理之前先需要了解Python中的类型(type).

查看对象的类型

我们可以使用 type(object) 来查看 object 的类型

obj="Hello"
print("obj的类型为", type(obj))

结果为:

obj的类型为 <class 'str'>

查看类的类型

上面可以看出变量 obj 的类型(type)为 str 类(class),那么 str 类本身的类型又是什么呢?让我们来看一下

print(type(str))

结果为:

<class 'type'>

哦, str 类的类型为 type

type的类型又是什么呢

那么你一定很好奇, type 的类似又是什么呢?让我们来看一下

print(type(type))

结果为:

<class 'type'>

你会发现, type 的类型还是 type 类。

也就是说 type 不仅是一般类(比如str,int)的元类,同时也是自己的元类。

元类中的那些特殊方法

type 类,作为Python中所有类(包括type本身)的默认元类,定义了一些特殊方法,可供自定义的元类覆盖,以完成特定的行为。

常见的几个特殊方法有:

__new__(cls,name,base,attr)
元类中, __new__ 会在你定义类的时候执行, 只执行一次
__init__(self, name, *args, **kwargs)
该元类的实例(也就是普通类)创建后被调用,用于为初始化实例的.
__call__(self, *args, **kwargs)
元类创建的实例(也就是普通类),构造普通类的对象时调用
class NewMeta(type):
    def __new__(*args, **kwargs):
        print('__new__() from NewMeta',args,kwargs)
        return type.__new__(*args, **kwargs)

    def __init__(self,name,*args,**kwargs):
        print('__init__() from NewMeta',args,kwargs)
        return type.__init__(self,name,*args,**kwargs)

    def __call__(self, *args, **kwargs):
        print('__call__() from NewMeta',args,kwargs)
        return type.__call__(self, *args, **kwargs)


class Test(object,metaclass=NewMeta):
    pass

print('---------------------------------')
Test()

结果为:

__new__() from NewMeta (<class '__main__.NewMeta'>, 'Test', (<class 'object'>,), {'__module__': '__main__', '__qualname__': 'Test'}) {}
__init__() from NewMeta ((<class 'object'>,), {'__module__': '__main__', '__qualname__': 'Test'}) {}
---------------------------------
__call__() from NewMeta () {}

class语法的实质是什么

要了解class语法的实质,首先要明白,python中的类其实也就是对象,只不过这个对象具有创建其他对象的能力而已。

既然类是一个对象,因此你就可以:

  • 赋值给变量
  • 作为函数参数进行传递
  • 为它增加属性
  • 对它进行拷贝

当解释器扫描到class语句后,根据整个class语句中找出定义该class的元类,该class继承的父类,以及class中包含的属性,然后通过执行

  =元类(类名,父类组成的元组,包含属性的字典)

来创建新类。

比如:

class MyType(type):
    pass

class Foo(metaclass=MyType):
    hello=True

class Bar(Foo):
    pass

其实就是

Foo=MyType('Foo', (), {'hello':True})

Bar=MyType('Bar', (Foo,), {})