python的元类

来源:互联网 发布:Linux 线程 sched_fifo 编辑:程序博客网 时间:2024/04/30 01:08

Python中的一切都是对象,无论是int,字符串,函数还是类。对象分为两类,实例对象和类对象。类对象就是类。我们可以这么理解,类实例化是实例对象,元类实例化就是类。

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

a=2print(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'>

故事如果到这里结束,就是证明了一个问题,python一切都是对象,简洁明了。

问题的下一个关键点,在于类的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转化为一个真实的数据库对象。