第七章 元类

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有没有对应的类呢,通过上面代码我们得知,是typetype就是一个元类

元类就是创建类的类

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)的查找,另外一个层则是类层(即元类层)的查找

results matching ""

    No results matching ""