python元类_Python之元类详细解析

'''1、什么是元类

在python中一切皆对象,那么我们用class关键字定义的类本身也是一个对象

负责产生该对象的类称之为元类,即元类可以简称为类的类

class Foo: # Foo=元类() #一切皆对象,类加括号产生对象

pass

2、为何要用元类

元类是负责产生类的,所以我们学习元类或者自定义元类的目的

是为了控制类的产生过程,还可以控制对象的产生过程

3、如何用元类'''

#1、储备知识:内置函数exec的用法

cmd="""x=1

def func(self):

pass"""class_dic={}exec(cmd,{},class_dic) #exec会将cmd字符串中的代码拿出来执行一次,将产生的名字丢掉事先定义好的class_dic空字典中

print(class_dic) #{'x': 1, 'func': }

#2、创建类的方法有两种#大前提:如果说类也是对象的话,那么用class关键字去创建类的过程也是一个实例化的过程#该实例化的目的是为了得到一个类,调用的是元类#2.1 方式一:用的默认的元类type

class People: #People=type(...)--------默认的元类type实例化出一个对象Pelple,实例化的结果也是一个对象

country='China'

def __init__(self,name,age):

self.name=name

self.age=agedefeat(self):print('%s is eating' %self.name)

peo=People('EGON',18)print(peo) #------------<__main__.People object at 0x000001F635282E10>*********调用类实例化出对象

print(type(People)) #------------*****************************************调用元类实例化出类

"""重点"""

#2.1.1 创建类的3个要素:类名,基类,类的名称空间

class_name='People' #类名,是一个字符串,---------由上面的class定义类我们知道,创建类的三要素:类名,基类,类的名称空间

class_bases=(object,) #基类,----------------------我们通过__bases__,知道基类是一个元组的形式

class_dic={} #类的名称空间,---------------通过__dict__,知道类的名称空间的是一个字典

class_body="""country='China'

def __init__(self,name,age):

self.name=name

self.age=age

def eat(self):

print('%s is eating' %self.name)""" #--------将类体代码放到一个字符串中

exec(class_body,{},class_dic)#执行字符传中的代码,将产生的名字方到class_dic的名称空间中,即之前定义类将产生的名字放到类的名称空间中

#准备好创建类的三要素#print(class_name) #-------People#print(class_bases) #-------(,)#print(class_dic) #-------{'country': 'China', '__init__': , 'eat': }

#People=type(类名,基类,类的名称空间) #调用元类就可以产生一个类这个对象

People1=type(class_name,class_bases,class_dic) #将事先定义好的类的三要素放到当做参数传给元类,调用元类即产生对象

print(People1) #--------自定义类产生的结果

obj1=People1('egon',18)print(People) #--------,class定义类产生的结果

obj=People('egon',18)

obj1.eat()

obj.eat()"""----------------------------------------重点----------------------------------------"""

#2.2 方式二:用的自定义的元类

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

def __init__(self,class_name,class_bases,class_dic):print(self) #现在是People

print(class_name)print(class_bases)print(class_dic)

super(Mymeta,self).__init__(class_name,class_bases,class_dic) #重用父类的功能

#分析用class自定义类的运行原理(而非元类的的运行原理):#1、拿到一个字符串格式的类名class_name='People'#2、拿到一个类的基类们class_bases=(obejct,)#3、执行类体代码,拿到一个类的名称空间class_dic={...}------------------前三步就是造类的三要素#4、调用People=type(class_name,class_bases,class_dic)----------------调用元类(类)产生类(对象)------------调用类产生对象

class People(object,metaclass=Mymeta): #People=Mymeta(类名,基类们,类的名称空间)------metaclass=Mymeta是自定义的元类名

country='China'

def __init__(self,name,age):

self.name=name

self.age=agedefeat(self):print('%s is eating' %self.name)"""----------------------------------------重点----------------------------------------"""

"""应用:自定义元类控制类的产生过程,类的产生过程其实就是元类的调用过程------(对象的产生过程就是调用类的过程)"""

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

def __init__(self,class_name,class_bases,class_dic): #在自定义类之上添加逻辑判断

if class_dic.get('__doc__') is None or len(class_dic.get('__doc__').strip()) == 0: #必须有文档注释,且不为空

raise TypeError('类中必须有文档注释,并且文档注释不能为空')if not class_name.istitle(): #类的首字母必须大写

raise TypeError('类名首字母必须大写')

super(Mymeta,self).__init__(class_name,class_bases,class_dic) #重用父类的功能

class People(object,metaclass=Mymeta): #People=Mymeta('People',(object,),{....})

"""这是People类"""country='China'

def __init__(self,name,age):

self.name=name

self.age=agedefeat(self):print('%s is eating' %self.name)#3 储备知识:__call__

classFoo:def __call__(self, *args, **kwargs):print(self) #<__main__.Foo object at 0x000002193E892E10>

print(args) #(1, 2, 3)----------------*args接收位置参数,存成元组的形式

print(kwargs) #{'x': 1, 'y': 2}---------**kwargs接收关键字参数,存成字典的形式

obj=Foo() #调用类不会自动触发,会在调用对象时自动触发,通过self也可以看出,是调用对象时自动触发

## 要想让obj这个对象变成一个可调用的对象,需要在该对象的类中定义一个方法__call__方法## 该方法会在调用对象时自动触发#obj(1,2,3,x=1,y=2) #调用对象时自动触发__call__方法,并将对象自动传入

"""-----------------------------------------------重点---------------------------------------------"""

#4、自定义元类来控制类的调用的过程,即类的实例化过程

classMymeta(type):def __call__(self, *args, **kwargs): #会在调用对象时自动触发,此时的对象时一个类,即People

#print(self) # self是People

#print(args)

#print(kwargs)

#return 123

"""调用类产生一个对象,发生两件事""" #和class定义类,调用类一样发生两件事

#1、先造出一个People的空对象

obj=self.__new__(self) #造出了一个自定义类People的空对象

#2、为该对空对象初始化独有的属性

#print(args,kwargs)

self.__init__(obj,*args,**kwargs) #对空对象进行初始化,空对象传入,以及参数原封不动的传入

#3、返回一个初始好的对象

return obj #将造出的对象返回,

'''**********************************看成一个对象************************************************'''

class People(object,metaclass=Mymeta): #自定义类People,元类是Mymeta,元类必须继承type类,否则就不是元类

country='China'

def __init__(self,name,age):

self.name=name

self.age=agedefeat(self):print('%s is eating' %self.name)def __new__(cls, *args, **kwargs): #对象自己中有__new__属性,先从对象自己的名称空间中找,自己没有在到自己的类中找

print(cls)#cls.__new__(cls) # 错误 #自己有调用了自己的__new__,这样就出现无线递归,所以会报错

obj=super(People,cls).__new__(cls) #自己中有,我们任然让其取继承父类中的__new__属性,来产生一个空对象,然后将对象初始化,拿到一个返回值

returnobj'''**********************************看成一个对象************************************************'''

"""-----------------------------------------------重点---------------------------------------------"""

#分析:调用Pepole的目的#1、先造出一个People的空对象#2、为该对空对象初始化独有的属性#obj1=People('egon1',age=18)#obj2=People('egon2',age=18)#print(obj1)#print(obj2)

#obj=People('egon',age=18)#print(obj.__dict__)#print(obj.name)#obj.eat()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值