目录
一、元类
1.1 什么是元类
-
在python中一切皆对象,类实际上就是一个一个的对象。
-
我们用class关键字定义的类本身也是一个对象,负责产生该对象的类称之为元类(元类可以简称为类的类)
-
type是内置的一个元类,所有的类都是由type实例化得到的。
-
如下,Person类也是一个对象,那么他一定是由一个类的实例化得到的,这个类就叫做元类。
class Person: def __init__(self,name): self.name = name def score(self): print('分数是100') a = Person # 类也是一等公民 p = a('ocean') print(p.name)
1.2 如何找元类
#利用print进行打印出
#type类是产生所有类的元类
print(type(p))#<class '__main__.Person'>
print(type(Person))#<class 'type'>
print(type(dict))#<class 'type'>
print(type(list))#<class 'type'>
print(type(str))#<class 'type'>
print(type(type))#<class 'type'>
二、class底层原理分析
-
class 类名,会把类构造出来。实际上实例化产生类,也是一个对象
-
类实例化产生对象,一定是:类名()
-
Person类是由type实例化产生,传入一堆参数
class Person: def __init__(self,name): self.name = name def score(self): print('分数是100') a = Person # 类也是一等公民 p = a('ocean') print(p.name)
-
type(object_or_name, bases, dict)
- object_or_name,类的名字,是一个字符串
- bases:是所有的父类(基类)
- dict:名称空间是一个字典
-
class底层就是调用type来实例化产生类(对象)
2.1 通过type来直接生成类
可以不用class关键字
type(object_or_name, bases, dict)
- object_or_name,类的名字,是一个字符串
- bases:是所有的父类(基类)
- dict:名称空间是一个字典
方法一
Person = type('Person',(object,),
{'school': 'hnsf'})
print(Person.__dict__)
#{'school': 'hnsf', '__module__': '__main__', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
方法二
exec("""
school = 'hnsf'
def __init__(self, name):
self.name = name
def score(self):
print('分数100分')
""",{},l)
Person = type('person',(object,),l)
print(Person.__dict__)
#{'school': 'hnsf', '__init__': <function __init__ at 0x000001C0FFD17318>, 'score': <function score at 0x000001C0FFD17168>, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'person' objects>, '__weakref__': <attribute '__weakref__' of 'person' objects>, '__doc__': None}
法三
def __init__(self,name):#魔法方法要先写好
self.name = name
Person = type('Person',(object,),
{'school': 'hnsf', '__init__':__init__})
print(Person.__dict__)
#{'school': 'hnsf', '__init__': <function __init__ at 0x00000226235673A8>, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
print(Person.__bases__)#(<class 'object'>,)
三、通过元类来控制类的产生
3.1自定义元类
自定义元类来控制类的产生,可以控制类名,可以控制类的继承父类
控制类的名称空间
自定义类必须继承type,写一个类继承type,这种类都叫元类
class Mymeta(type):# 产生的类作为一个对象,传给元类
def __init__(self,*args,**kwargs):
print(*args)#Person () {'__module__': '__main__', '__qualname__': 'Person', 'school': 'hnsf', '__init__': <function Person.__init__ at 0x000001C81E7D7558>, 'score': <function Person.score at 0x000001C81E7D75E8>}
print(**kwargs)
metaclass = Mymeta#指定这个类生成的时候,用自己写的Mymeta这个元类
class Person(metaclass=Mymeta):
school = 'hnsf'
def __init__(self,name):
self.name = name
def score(self):
print('ok')
class Mymeta(type):
def __init__(self, name, bases, dic):
print(self)
# print(name)# 类名,Person
print(self.__name__) # 类名,Person
# print(bases)# 类的父类,(<class 'object'>,)
print(self.__bases__) # 类的父类,(<class 'object'>,)
# print(dic)
print(self.__dict__) # 类的名称空间,{'__module__': '__main__', '__qualname__': 'Person', 'school': 'hnsf', '__init__': <function Person.__init__ at 0x000002D6F6337558>, 'score': <function Person.score at 0x000002D6F63375E8>}
metaclass = Mymeta # 指定这个类生成的时候,用自己写的Mymeta这个元类
class Person(object, metaclass=Mymeta):
school = 'hnsf'
def __init__(self, name):
self.name = name
def score(self):
print('ok')
练习一:
对产生的类进行限制,控制类必须以sb开头
class Mymeta(type):
def __init__(self, name, bases, dic):
if not name.startswith('sb'):
raise Exception('类名没有以sb开口')
metaclass = Mymeta # 指定这个类生成的时候,用自己写的Mymeta这个元类
class sbPerson(object, metaclass=Mymeta):
school = 'hnsf'
def __init__(self, name):
self.name = name
def score(self):
print('ok')
练习二,类必须加注释
类的名称空间中的key值'__doc__'代表注释
class Mymeta(type):
def __init__(self, name, bases, dic):
print(self.__dict__["__doc__"])
metaclass = Mymeta # 指定这个类生成的时候,用自己写的Mymeta这个元类
class sbPerson(object, metaclass=Mymeta):
"""
我已经注释
"""
school = 'hnsf'
def __init__(self, name):
self.name = name
def score(self):
print('ok')
class Mymeta(type):
def __init__(self, name, bases, dic):
doc = self.__dict__["__doc__"]
if not doc:
raise Exception('你的类没有加注释')
else:
print(doc)
metaclass = Mymeta # 指定这个类生成的时候,用自己写的Mymeta这个元类
class sbPerson(object, metaclass=Mymeta):
"""
我已经注释
"""
school = 'hnsf'
def __init__(self, name):
self.name = name
def score(self):
print('ok')
四、通过元类控制类的调用过程
-
要想让obj这个对象变成一个可调用的对象,需要在该对象的类中定义一个方法__call__方法,该方法会在调用对象时自动触发
-
控制类的调用过程,实际是在控制:对象的产生
class Mymeta(type): def __call__(self, *args, **kwargs): print('ocean') return 95 class Person(object,metaclass=Mymeta): school = 'nasf' def __init__(self,name): self.name = name def score(self): print('100') p = Person('chen')#ocean print(p)#ocean 95
class Person(): school = 'nasf' def __init__(self,name): self.name = name def score(self): print('100') def __call__(self, *args, **kwargs): print('ocean') p = Person('chen')#自动触发__init__的执行
class Person(): school = 'nasf' def __init__(self,name): self.name = name def score(self): print('100') def __call__(self, *args, **kwargs): print('ocean111') p = Person('chen') p()# 当元类没有自定义__call__的时候,而且自身定义了__call__的时候,那么对象加()会触发
#先触发元类的__call__ # 当自身和自定义的元类都写了__call__方法的时候,先触发元类的__call__,并且不会生成对象 class Mymeta(type): def __call__(self, *args, **kwargs): print('ocean') # return 95 # # # p = Person('chen')#ocean # print(p)#ocean 95 class Person(metaclass=Mymeta): school = 'nasf' def __init__(self,name): self.name = name def score(self): print('100') def __call__(self, *args, **kwargs): print('ocean111') p = Person('chen')#不会生成p对象
练习:给我吧对象中的所有属性都设置成私有的
分析:
class Mymeta(type): def __call__(self, *args, **kwargs): #实例化产生一个Person类的对象,借助__new__来产生, # 需要把类传过去,才能产生对象,只不过是空的 obj = object.__new__(self) class Person(object,metaclass=Mymeta): school = 'hnsf' def __init__(self,name): self.name = name p = Person('name') print(p)#None
class Mymeta(type): def __call__(self, *args, **kwargs): #实例化产生一个Person类的对象,借助__new__来产生, # 需要把类传过去,才能产生对象,只不过是空的 obj = object.__new__(self) #调用__init__方法完成初始化 #类来调用__init__方法,就是一个普通函数,有几个参数就传几个参数 # self.__init__(obj,*args,**kwargs) #对象来调用__init__方法,对象的绑定方法,会把自身传过去 obj.__init__(*args,**kwargs) print(obj) return obj class Person(object,metaclass=Mymeta): school = 'hnsf' def __init__(self,name): self.name = name p = Person('name') print(p) print(p.name)
把对象的所有的属性变为私有
class Mymeta(type): def __call__(self, *args, **kwargs): obj = object.__new__(self) obj.__init__(*args,**kwargs) print(obj.__dict__)#{'name': 'ocean'} obj.__dict__ ={'_%s__%s'%(self.__name__,k):v for k,v in obj.__dict__.items()} print(obj.__dict__)#{'_Person__name': 'ocean'} return obj class Person(object,metaclass=Mymeta): school = 'hnsf' def __init__(self,name): self.name = name p = Person(name='ocean') print(p.__dict__)#{'_Person__name': 'ocean'}
五、有了元类之后的属性查找
- 类的属性查找顺序:先从类本身中找--->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)