元类及其原理
什么是元类
在python中,一切都是对象,那么类肯定也是一个一个对象
如果类是对象的话,那他一定是由一个实例化得到,这个类就叫做元类。也就是说产生类的类,叫做元类
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))
上述结构都为<class 'type'>,也就是说,在一般情况下,元类为type。type是一个内置的元类,所有的类都是有type实例化得到
class底层原理分析
class+类名,会把类构造出来,但是,实际上则是元类实例化产生类这个对象。
我们也可以用type来直接产生类,而不用class关键字
type() 掉用类的__init__方法
type(object_or_name, bases, dict)
object_or_name:类的名字,是个字符串
bases:是它的所有父类,基类
dict:名称空间,
那么我们就可以定义一个简单的Person类
def __init__(self,name):
self.name=name
Person=type('Person',(object,),{'school':'oldboy','__init__':__init__})
我们也可以用exec()方法来实现最后字典的输入
l={}
exec('''
school='school'
def __init__(self,name):
self.name=name
def score(self):
print('分数是100')
''',{},l)
Person=type('Person',(object,),l)
通过元类来控制类的产生
自定义元类,来控制类的产生,可以控制类名,可以控制类的继承父类,控制类的名称空间自定义元类必须继承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开头')
class sb_Person(object,metaclass=Mymeta):
school='雄英高中'
def __init__(self,name):
self.name=name
def score(self):
print('分数是100')
如果上述代码类名不以sb开头,则会抛出'类名没有以sb开头'异常
同样我们也可以办到让类必须添加注释
查询注释的方法为类名._doc_
class Mymeta(type):
def __init__(self,name,bases,dic):
print(self.__dict__['__doc__'])
doc=self.__dict__['__doc__']
if not doc:
# 没有加注释
raise Exception('你的类没有加注释')
#metaclass=Mymeta 指定这个类生成的时候,用自己写的Mymeta这个元类
class Person(object,metaclass=Mymeta):
'''
注释
'''
school='音乃木坂学院'
def __init__(self,name):
self.name=name
def score(self):
print('分数是100')
控制类的调用过程
控制类的调用过程,实际上是在控制对象的产生
我们在使用__call__的时候,如果采用对象加()的话,就会调用类里__call__方法
那么如果我们采用类加()的时候呢?很明显我们会调用元类里的__call__方法
我们可以因此而不改变类内的东西,只用元类来使该类里的属性隐藏
class Mymeta(type):
def __call__(self, *args, **kwargs):
obj=object.__new__(self)
# self.__init__(obj,*args, **kwargs) # 也可以用
obj.__init__(*args, **kwargs)
# print(obj.__dict__)
obj.__dict__={ '_%s__%s'%(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) # 会报错,因为已经被隐藏
有了元类之后的属性查找顺序
类的属性查找顺序:先从类本身中找--->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)