什么是元类
元类是python面向对象编程的深层魔法,很多人都不得要领。
在python中一切皆是对象,用class定义得类本身也是一个对象,负责产生该对象的类称之为元类,即元类可以简称为类的类。
简单来说,只要继承了type,他就是元类
#Person也是一个对象,那么他一定是由一个类实例化得到的,这个类也就是元类
classPerson:pass
p1=Person
# type类 是产生所有类的元类print(type(Person))print(type(list))print(type(dict))print(type(object))#
为什么用到元类
元类是负责产生类的,所以我们学习元类或者自定义元类的目的,是1、为了控制类的产生过程,2、还可以控制对象的产生过程。
class创建类
classPeople: # People = type()
country= 'China'
def __init__(self, name, age):
self.name=name
self.age=agedefeat(self):print('%s is eating' % self.name)
class加类名,就会把类构造出来
用class关键字创建一个类,用默认的元类type。
type元类
Person类是有type实例化产生的,向type传了一堆参数,然后type()类调用__init__方法,就会创建一个类。
type()创建类格式:
type(object, bases(继承的基类), dict)
object: object(所有基类)orname (类名:你需要创建的名字),类的名字,是个字符串
base:是他的所有的父类 (元组的形式)、基类
dict:名称空间,是一个字典;
创建类的三要素:类名、基类、类的名称空间
通过type 直接产生的类,不用class关键字
def __init__(self, name, age):
self.name=name
self.age=age#名称空间是一个字典#创建类 People = type(类名,基类,类的名称空间)
Person = type('Person', (object, ), {'school': 'hnnu','__init__': __init__,'sex':'boy'})#创建对象
p = Person('randy',12)print(p.say(p))
通过元类来控制类的产生
#自定义元类马? ilil
# Mymeta就是一个元类,因为它继承了type
classMymeta(type):def __init__(self, name, base, dict):print(name) #类名
print(base) #基类
print(dict) #名称空间
"""通过class 创建的类继承,自定义的元类,在Person中定义第一个参数表示类的名称,第二个参数表示继承的基类,而类中的代码dict则是,产生的名称空间。"""
class Ren(object, metaclass=Mymeta):
school= 'hlxy'
def __init__(self, name):
self.name=namedefscore(self):print('score is 100')
p= Ren('sb')
例子1
classMymeta(type):def __init__(self, name, base, dic):#练习一 加限制, 限制类名必须以sb开头
print(name)if not name.startswith('heihei'):raise Exception('类名没有以heihei开头!!!!')class heihei_Ren(object, metaclass=Mymeta):
school= 'hei'
def __init__(self, name):
self.name=nameprint(2)defscore(self):print('分数为10000')
p1= heihei_Ren('Jac')
例子2
classMymeta(type):def __init__(self, name, base, dic):print(self.__dict__) #产生的名称空间是类
print(dic)
doc= self.__dict__['__doc__']print("元类")if notdoc:raise Exception("必须有注释")print(doc)class Person(object, metaclass=Mymeta):"""我已经注释了"""school= 'hnnu'
def __init__(self, name):print("自己")
self.name=namedefscore(self):print("分数是: 100")#继承元类,首先会先进入元类中的__init__在返回来执行p1实例,然后再执行p1实例里面的__init__
p1 = Person('ran')
通过控制类产生的模板
classMymeta(type):def __init__(self, name, base, dic):if name == 'Person':raise Exception("名称错误")class Person1(metaclass=Mymeta):def __init__(self, name, age):
self.name=name
self.age=age
p= Person1('laowang', 19)
通过元类控制类得调用过程(控制创建类对象的过程)
想要让obj这个对象变成一个可调用的对象,需要在该对象的类中定义一个方法,__call__方法,该方法会在调用对象的时候,自动触发。
我们之前说类实例化第一个调用的是__init__,但__init__其实不是实例化一个类的时候第一个被调用的方法。
当时候Person(name,age)这样表达式来实例化一个类的时候,最先被调用的方法其实是__new__方法。
__new__方法接受的参数虽然和__init__一样,但__init__是在实例创建之后调用的,而__new__正是创建实例的方法。
把对象属性都变成私有属性
classMymeta(type):def __call__(self, *args, **kwargs):print("__call__ 第一")#产生空对象
obj = object.__new__(self)#调用子类__init__
obj.__init__(*args, **kwargs)#名称空间创建完成之后进行处理
#会进入self==> person类中__init__然后在回来
obj.__dict__ = {f"_{self.__name__}__{k}": v for k, v in obj.__dict__.items()}#print("123456", obj.__dict__)
#print("__call__ ", obj.__dict__)
returnobjclass Person(object, metaclass=Mymeta):def __init__(self, name):print("___init__ 第二")
self.name=namedefscore(self):print('分数是100')
p= Person(name='randy')print(p.__dict__)#print(p._Person__name)
自定义元类后继承顺序
结合python继承得实现原理+元类重新看属性得查找是什么样子
在学完元类之后,就发现每一个定义的clss都是一个对象(包括object类本身也是元类type得一个实例,可以用type(object))查看,我们也学习过继承的实现原理。
class Mymeta(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
n = 444
def __call__(self, *args,**kwargs): #self=
obj = self.__new__(self)
self.__init__(obj, *args, **kwargs)returnobjclassBar(object):
n= 333
classFoo(Bar):
n= 222
class OldboyTeacher(Foo, metaclass=Mymeta):
n= 111school= 'oldboy'
def __init__(self, name, age):
self.name=name
self.age=agedefsay(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、先在对象层:Oldboy——Foo——Bar——object2、然后元类层:Mymeta——type
上述总结: 分析下元类Mymeta中__call__的self.__new__的查找
C3算法
总结
继承元类,首先回进入元类中的__init__在返回来执行自己的__init__
控制类产生模板
#控制类产生模板
classMymeta(type):def __init__(self, name, base, dic):if self.name ==Person:raise Exception("名称错误")class Person(metaclass=Mymeta):def __init__(self, name, age):
self.name=name
self.age=age
p= Person('laowang', 19)
控制对象的产生
classMymeta(type):def __call__(self, *args, **kwargs):#第一步产生空对象obj=object.__new__(self)#第二部初始化空对象,把初始值放到对象中
obj.__init__(*args, **kwargs)#第三步返回对象
returnobjclass Person(metaclass=Mymeta):def __init__(self,name):
self.name=namedef __call__(self, *args, **kwargs):print('xxx')
p=Person('jackson6666')print(p.name)
classMymeta(type):
def__call__(self,*args,**kwargs):
# 第一步产生空对象obj=object.__new__(self)
# 第二部初始化空对象,把初始值放到对象中obj.__init__(*args,**kwargs)
# 第三步返回对象returnobj
classPerson(metaclass=Mymeta):
def__init__(self,name):
self.name=name
def__call__(self,*args,**kwargs):
print('xxx')
p=Person('jackson6666')
print(p.name)