元类

1. 元类是什么

# 一切皆对象:类实际上一个一个对象
# Penson类也是个对象,那他一定是由一个类实例化得到,这个类,就叫元类
# type是内置的一个元类,所有的类都是由type实例化得到
# 产生类的类,叫元类

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

p = Person('nick')

a = Person
p1 = a('nick')
print(p1.name)

# 如何找元类
print(type(p))
# 同理:type类是产生所有类的元类
print(type(Person))
print(type(dict))
print(type(list))
print(type(str))
print(type(object))

print(type(type))

2. class底层原理分析


# class 类名   会把类构造出来
# 实际上是:元类实例化产生类 这个对象
# 类实例化产生对象,一定是:类名()
# Person 类是由type实例化产生,传一堆参数
# type() 调用类的__init__方法
# type()
# type(object_or_name,bases,dict)
# object_or_name:类的名字,是个字符串
# bases:是他的所有父类,基类
# dict:名称空间,是一个字典

# 通过type来直接产生类,不用class关键字了
l = {}
exec('''
school = 'oldboy'
def __init__(self,name):
    self.name = name
def score(self):
    print('分数是100')
''',{},l)
def __init__(self,name):
    self.name = name

# Person = type('Person',(object,),{'school':'oldboy','__init__':__init__})

Person = type('Person',(object,),l)

print(Person.__dict__)
print(Person.__bases__)

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

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

class Person:
    school = 'oldboy'
    def __init__(self,name):
        self.name = name
    def score(self):
        print('分数是100')
a = Person
p = Person('nick')
print(p.name)

# exec()  eval() 的区别
l = {}
exec('''
school = 'oldboy'
def __init__(self,name):
    self.name = name
def score(self):
    print('分数是100')
''',{},l)

print(l)

g = {'x':1,'y':2}
l = {}
exec('''
global x
x = 100
z = 200
m = 300
''',g,l)
print(g)
print(l)

3. 通过元类来控制类的产生

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

# type
# 自定义元类必须继承type,写一个类继承type  这种类都叫元类

class Mymeta(type):
    # def __init__(self,*args,**kwargs):
    def __init__(self,name,bases,dic):
        # self就是Person类
        print(name)
        print(bases)
        print(dic)
        # 练习一:加限制 控制类名必须以sb开头
        if not name.startswith('sb'):
            raise Exception('类名没有以sb开头')
        # 练习二:类必须加注释
        print(self.__dict__['__doc__'])

# metaclass = Mymeta 指定这个类生成的时候,用自己写的Mymeta这个元类
class Person(object,metaclass=Mymeta):
    '''
    注释
    '''
    school = 'oldboy'
    def __init__(self,name):
        self.name = name
    def score(self):
        print('分数是100')

p = Person()

class Mymeta(type):
    def __init__(self,name,bases,dic):
        print(self.__dict__['__doc__'])
        doc = self.__dict__['__doc__']
        if not doc:
            # 没有加注释
            raise Exception('你的类没有加注释')
class Person(object,metaclass=Mymeta):
    '''
    我加了注释
    '''
    school = 'oldboy'
    def __init__(self,name):
        self.name = name
    def score(self):
        print('分数是100')

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

# __call__
# 控制类的调用过程,实际上在控制 对象的产生
class Mymeta(type):
    def __call__(self, *args, **kwargs):
        # print('xxx')
        return 1

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

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

class Person():
    school = 'oldboy'
    def __init__(self,name):
        self.name = name
    def score(self):
        print('分数是100')
    def __call__(self, *args, **kwargs):
        print('xxx')

p = Person('nick')  # 自动触发init的执行
# 先触发元类的__call__
p()

# __new__

# 练习:把对象中的所有属性都设置成私有的
# 分析
class Mymeta(type):
    def __call__(self, *args, **kwargs):
        # self是Person这个类
        print(args)
        print(kwargs)
        # return self(*args)  # 这里不行,会递归
        self.__new__(self)
        # 实例化产生一个Person类的对象,借助__new__来产生,需要把类传过去,才能产生对象
        # obj是Person类的对象,只不过是空的
        obj = object.__new__(self)
        # obj = self.__new__(self)
        # 调用__init__方法完成初始化
        # 类来调用__init__方法,就是个普通函数,有几个参数就传几个参数
        # self.__init__(*args,**kwargs)
        # 对象来调用__init__方法,对象的绑定方法,就会把自身传过来
        obj.__init__(*args,**kwargs)
        print(obj)
        return obj


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

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

# 把对象所有的属性都变成私有
class Mymeta(type):
    def __call__(self, *args, **kwargs):
        obj = object.__new__(self)
        obj.__init__(*args,**kwargs)
        print(obj.__dict__)
        obj.__dict__ = {f'_{self.__name__}__{k}':v for k,v in obj.__dict__.items()}
        print(obj.__dict__)
        return obj

class Person(object,metaclass=Mymeta):
    school = 'oldboy'
    def __init__(self,name):
        self.name = name
    def score(self):
        print('分数是100')
p = Person(name = 'nick')
print(p.__dict__)
# print(p.name)
print(p)
# print(p.name)

5. 有了元类之后的属性查找

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

class Mymeta(type):
    n=444

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


class Bar(object):
    # n=333
    pass

    # def __new__(cls, *args, **kwargs):
    #     print('Bar.__new__')

class Foo(Bar):
    # n=222
    pass

    # def __new__(cls, *args, **kwargs):
    #     print('Foo.__new__')

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)


    # def __new__(cls, *args, **kwargs):
    #     print('OldboyTeacher.__new__')


o=oldboyTeacher('egon',18) #触发oldboyTeacher的类中的__call__方法的执行,进而执行self.__new__开始查找
print(oldboyTeacher.n)
# print(o.n)
原文地址:https://www.cnblogs.com/yushan1/p/11453840.html