第七章 元类
1 什么是元类 metaclass
元类是Python面向对象里最难理解,也是最难使用的魔术代码。正常情况下,使用元类的情况也非常至少。但是,我们还是细细地道来什么是元类
我们知道,"Python中一切皆对象",如下面代码,我们知道t1
是个对象, 那Person
是什么呢? 有人说是类啊,废话当然是类啊,但是我们前面讲过"一切皆对象",那么,类Person
是不是也是个对象呢? 还真是的
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def say(self):
print('打扎好,我似%s,今年%s岁' %(self.name, self.age))
p1 = Person('丹丹', 10)
type(p1) # <class '__main__.Person'>
type(Person) # <class 'type'>
所有的对象都有一个对应的类,那么Person
有没有对应的类呢,通过上面代码我们得知,是type
。type
就是一个元类
元类就是创建类的类
print(type(int)) # <class 'type'>
print(type(str)) # <class 'type'>
print(type(list)) # <class 'type'>
print(type(dict)) # <class 'type'>
print(type(tuple)) # <class 'type'>
2 使用 元类type构建一个类
type(class_name, base_tuple, attr_dict)
参数1:class_name: 类名
参数2:base_tuple: 父类组成的元祖
参数3: attr_dict: 类内定义的名字空间,类属性组成的字典
class Person:
def say(self):
print('how are you')
def sleep(self):
print('i love sleep')
def fn(self):
print('我爱学习')
Student = type('Student', (Person, ), {'school':'清华大学', 'study':fn})
s = Student()
print(s)
s.say()
s.sleep()
s.study()
print(s.school)
3 自定义元类
一个类没有声明自己的元类,默认他的元类就是type,除了使用内置元类type,我们也可以通过继承type来自定义元类,然后使用metaclass关键字参数为一个类指定元类
class Mymeta(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
pass
class Teacher(object,metaclass=Mymeta):
school='交通大学'
def __init__(self,name,age):
self.name=name
self.age=age
def say(self):
print('%s says How Are You' %self.name)
# 上面定义类的方式,等同于
Teacher=Mymeta('Teacher',(object),{...})
自定义元类可以控制类的产生过程,类的产生过程其实就是元类的调用过程,即Teacher=Mymeta('Teacher',(object),{...})
,调用Mymeta会先产生一个空对象Teacher,然后连同调用Mymeta括号内的参数一同传给Mymeta下的__init__
方法,完成初始化,于是我们可以
class Mymeta(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
def __init__(self,class_name,class_bases,class_dic):
super(Mymeta, self).__init__(class_name, class_bases, class_dic) # 重用父类的功能
if class_name.islower():
raise TypeError('类名%s请修改为驼峰体' %class_name)
if '__doc__' not in class_dic or len(class_dic['__doc__'].strip(' \n')) == 0:
raise TypeError('类中必须有文档注释,并且文档注释不能为空')
class Teacher(object,metaclass=Mymeta):
"""
类Teacher的文档注释
"""
school='清华大学'
def __init__(self,name,age):
self.name=name
self.age=age
def say(self):
print('%s says How Are You' %self.name)
4 再看属性查找
结合python继承的实现原理+元类重新看属性的查找应该是什么样子呢???
class Mymeta(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
n=444
class Bar(object):
n=333
class Foo(Bar):
n=222
class Student(Foo,metaclass=Mymeta):
n=111
s = Student()
print(s.n)
于是属性查找应该分成两层,一层是对象层(基于c3算法的MRO)的查找,另外一个层则是类层(即元类层)的查找