前言
对于元类有一个通俗易懂又颇具禅意的比喻:
道生一,一生二,二生三,三生万物
- 道 即是 type
- 一 即是 metaclass(元类,或者叫类生成器)
- 二 即是 class(类,或者叫实例生成器)
- 三 即是 instance(实例)
- 万物 即是 实例的各种属性与方法,我们平常使用python时,调用的就是它们。
“一”就是今天要学习的重点–元类(Meta Class)。
正文
什么是元类(Meta Class)
简单的讲,元类创建了Python中所有的对象。
我们说Python是一种动态语言,而动态语言和静态语言最大的不同,就是函数和类不是编译时定义的,而是运行时动态创建的。
class的定义是运行时动态创建的,而创建class的方法就是使用type()函数。
通过type()函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()函数创建出class。
除了使用type()动态创建类以外,要控制类的创建行为,还可以使用metaclass,直译为元类。
当我们定义了类以后,就可以根据这个类创建出实例,所以:先定义类,然后创建实例。但是如果我们想创建出类呢?那就必须根据metaclass创建出类,所以:先定义metaclass,然后创建类。所以,metaclass允许你创建类或者修改类。换句话说,你可以把类看成是metaclass创建出来的“实例”。
动态创建类
下面来举例集几种类的创建方式
- 函数创建
- type()创建
函数创建:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def create_animal(type):
if type == 'Dog':
# 创建类
class Dog(object):
pass
return Dog
elif type == 'Cat':
class Cat(object):
pass
return Cat
Dog = create_animal("Dog")
print(type(Dog))
dog = Dog()
print(type(dog))
输出结果:
1
2
<class 'type'>#类类型 <br/>
<class '__main__.create_animal.<locals>.Dog'>#对象类型
这里通过调用函数传图不同的参数,来创建不同的类,创建出返回的是类的引用,并不是对象,我们可以通过返回的类来创建对象。
type()创建:
1
2
3
4
5
6
7
8
class Test1(object):
pass
Test2 = type("Test2", (object,), {})
print(type(Test1))
print(type(Test2))
输出结果:
1
2
<class 'type'>
<class 'type'>
可以看出两种创建方式是相同的效果,说到这里我们大家应该都明白了,原来type就是创建类的一个方法,python用它来创建类,也就是说他是所有类的元类,例如在pyhton中是不是还有int,str…等等类型,int就是用来创建整数的类,而str就是用来创建字符串的类,这里的type也是,他就是python用来创建类的类(元类)。
自定义元类
自定义类的的目的,就是拦截类的创建,然后修改一些特性,然后返回该类。感觉是装饰器干的事情,只是装饰器是修饰一个函数,同样是一个东西进去,然后被额外加了一些东西,最后被返回。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def upper_attr(class_name, class_parents, class_attr):
"""
返回一个对象,将属性都改为大写的形式
:param class_name: 类的名称
:param class_parents: 类的父类tuple
:param class_attr: 类的参数
:return: 返回类
"""
# 生成了一个generator
attrs = ((name, value) for name, value in class_attr.items() if not name.startswith('__'))
uppercase_attrs = dict((name.upper(), value) for name, value in attrs)
return type(class_name, class_parents, uppercase_attrs)
__metaclass__ = upper_attr
pw = upper_attr('Trick', (), {'bar': 0})
print hasattr(pw, 'bar')
print hasattr(pw, 'BAR')
print pw.BAR
输出结果:
False
True
可以从上面看到,实现了一个元类(metaclass), 然后指定了模块使用这个元类来创建类,所以当下面使用type进行类创建的时候,可以发现小写的bar参数被替换成了大写的BAR参数,并且在最后调用了这个类属性并,打印了它。
总结
类其实是能够创建出类实例的对象。好吧,事实上,类本身也是实例,当然,它们是元类的实例。
Python中的一切都是对象,它们要么是类的实例,要么是元类的实例,除了type。type实际上是它自己的元类,在纯Python环境中这可不是你能够做到的,这是通过在实现层面耍一些小手段做到的。其次,元类是很复杂的。对于非常简单的类,你可能不希望通过使用元类来对类做修改。
参考资料
此次学习主要依赖于下面技术网站:
https://stackoverflow.com/questions/100003/what-are-metaclasses-in-python
http://blog.jobbole.com/21351/