元类

什么是元类

因为在python中一切皆对象,类实际上就是一个一个的类

type是内置的一个元类,所有的类都是由type实例化得到

class Person:
    def __init__(self,name):
        self.name=name
    def score(self):
        print('分数是100')

p=Person('nick')

如Person类也是个对象,那他一定是由一个类实例化得到,这个类,就叫元类

同理:type类是产生所有类的元类

class底层原理

通过type来直接产生类,不用class关键字了

l ={}
exec('''
school = 'oldboy'
def __init__(self,name):
    self.name= name

def score(self):
    print('分数是100')

''',{},l)

Person = type('Person',(object,),l)  ##type产生的类
print(Person.__bases__)
#   ->(<class 'object'>,)
p = Person('nick')
print(p.name)
#   ->nick

class 底层就是调用type来实例化产生类(对象)

Person 类是由type实例化产生,传一堆参数

自定义元类控制类的产生

自定义元类:来控制类的产生:可以控制类名,可以控制类的继承父类,控制类的名称空间

自定义元类必须继承type>>>

class Mymeta(type):

    #type(name, bases, dict) -> a new type
    def __init__(self,name,bases,dic):
        print(name)
        print(bases)
        print(dic)

class Person(object,metaclass=Mymeta):

#当python解释器遇到metaclass会去使用Mymeta去创建这个类
#这里可以把person类看成一个对象

    school = 'heima'
    def __init__(self,name):
        self.name = name
    def score(self):
        print('分数是100')

p = Person('nick')
print(p.name)

结果:
    
# -> Person
# ->(<class 'object'>,)
# ->{'__module__': '__main__', '__qualname__': 'Person', 'school': 'heima', '__init__': <function Person.__init__ at 0x0000028A31973EA0>, 'score': <function Person.score at 0x0000028A31973F28>}
# ->nick

通过元类控制类的调用过程

控制类的调用过程,实际上在控制:对象的产生

# 触发元类的__call__,无法调用p.name

class Mymeta(type):
    def __call__(self, *args, **kwargs):
        # print('xxx')

        return 1

class Person(object,metaclass=Mymeta):
    school='zheda'
    def __init__(self,name):
        self.name=name
    def score(self):
        print('分数是100')

p=Person('nick')
print(p)
# print(p.name)  ->报错

结果:1

_new_

__new__方法(第一个执行)先于__init__方法执行

__new__方法是传入类(cls),而__init__方法传入类的实例化对象(self),而有意思的是,__new__方法返回的值就是一个实例化对象(ps:如果__new__方法返回None,则__init__方法不会被执行,并且返回值只能调用父类中的__new__方法,而不能调用毫无关系的类的__new__方法)。

class A:
    pass


class B(A):
    def __new__(cls):
        print("__new__方法被执行")
        return cls.__new__(cls)

    def __init__(self):
        print("__init__方法被执行")


b = B()

#注意:new() 函数只能用于从object继承的新式类。

有了元类后的属性查找

class Mymeta(type):  # 只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
    n = 444

    def __call__(self, *args,
                 **kwargs):  #self=<class '__main__.OldboyTeacher'>
        obj = self.__new__(self)
        self.__init__(obj, *args, **kwargs)
        return obj


class Bar(object):
    n = 333


class Foo(Bar):
    n = 222


class OldboyTeacher(Foo, metaclass=Mymeta):
    n = 111

    school = 'oldboy'

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def say(self):
        print('%s says welcome to the oldboy to learn Python' % self.name)


print(
    OldboyTeacher.n
)  # 自下而上依次注释各个类中的n=xxx,然后重新运行程序,发现n的查找顺序为OldboyTeacher->Foo->Bar->object->Mymeta->type

1.类的属性查找顺序:先从类本身中找--->mro继承关系去父类中找---->去自己定义的元类中找--->type中--->报错
2.对象的属性查找顺序:先从对象自身找--->类中找--->mro继承关系去父类中找--->报错

posted @ 2019-09-03 16:12  后排男生  阅读(104)  评论(0编辑  收藏  举报