python的元类

Python中的一切都是对象,无论是int,字符串,函数还是类。
对象分为两类,实例对象和类对象。类对象就是类。(权威的说法是metaclasses,classes,instance三类对象)
我们可以这么理解,类实例化是实例对象,元类实例化就是类。

type是python内置的唯一元类。当然你可以自己开发元类。int str等则是python内置的类。一切类都是元类的实例化,包括元类自己。

a=2
print(a.__class__)//python3输出<class 'int'>
print(a.__class__.__class__)//python3输出<class 'type'>
print(type.__class__)//python3输出<class 'type'>

既然type是元类,那么我们实例化type就可以得到一个类。实际上也确实如此

def fn(self, name='world'): # 先定义函数
    print('Hello, %s.' % name)
Hello = type('Hello', (object,), dict(hello=fn))//Hello已经是一个类了

h = Hello()
print(h.__class__)//输出<class '__main__.Hello'>

这里写图片描述
上面这张图中,其中实线表示 is-kind-of 的关系 ,虚线表示is-instance-of的关系。

问题的下一个关键点,在于类的metaclass属性。并不是所有类都有metaclass,除非你显示的指定它。如果你在类中指定他,他将在该类中有效。如果你在模块中指定它,则对于整个模块的所有类都有效。

metaclass可以在模块和类中定义。可以是一个方法,也可以是一个类。如果他是一个方法,则他应该返回一个类对象,如下例子所示:

# 元类会自动将你通常传给‘type’的参数作为自己的参数传入
def upper_attr(future_class_name, future_class_parents, future_class_attr):
    '''返回一个类对象,将属性都转为大写形式'''
    #  选择所有不以'__'开头的属性
    attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
    # 将它们转为大写形式
    uppercase_attr = dict((name.upper(), value) for name, value in attrs)

    # 通过'type'来做类对象的创建
    return type(future_class_name, future_class_parents, uppercase_attr)

__metaclass__ = upper_attr  #  这会作用到这个模块中的所有类

class Foo(object):
    # 我们也可以只在这里定义__metaclass__,这样就只会作用于这个类中
    bar = 'bip'

如果metaclass和他的名字元类一样是一个类,如下例子所示,此时,要求其__new__方法必须返回一个类对象。

# 请记住,'type'实际上是一个类,就像'str'和'int'一样
# 所以,你可以从type继承
class UpperAttrMetaClass(type):
    # __new__ 是在__init__之前被调用的特殊方法
    # __new__是用来创建对象并返回之的方法
    # 而__init__只是用来将传入的参数初始化给对象
    # 你很少用到__new__,除非你希望能够控制对象的创建
    # 这里,创建的对象是类,我们希望能够自定义它,所以我们这里改写__new__
    # 如果你希望的话,你也可以在__init__中做些事情
    # 还有一些高级的用法会涉及到改写__call__特殊方法,但是我们这里不用
    def __new__(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr):
        attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
        uppercase_attr = dict((name.upper(), value) for name, value in attrs)
        return type(future_class_name, future_class_parents, uppercase_attr)

因为上面的元类是直接从type继承的,所以上面代码最后一句可以改为

return type.__new__(upperattr_metaclass, future_class_name, future_class_parents, uppercase_attr)

或者


return super(UpperAttrMetaclass, cls).__new__(cls, name, bases, uppercase_attr)

元类是动态改变类的属性名和属性值的办法。diango中的model.py就采用这种办法,从而将用户的model.py转化为一个真实的数据库对象。

阅读更多
换一批

没有更多推荐了,返回首页