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转化为一个真实的数据库对象。