Python是一门动态语言(Python在定义变量的时候,并没有指定数据类型),反射机制被视为动态语言的关键.
a=HaHab=c=3.14d={a:,b:}什么是反射?
指的是在程序运行过程中可以动态获取对象的信息.当我在调用上述变量的时候,程序需要自动的识别变量的类型:
res1=a*d#通过反射机制,发现a是字符串,d是字典,无法相乘res2=b*c#通过反射机制,程序能正常执行为何要用反射?
deffunc(obj):obj.xfunc(10)
给func传10,10调用x方法.程序报错,10没有x方法.那么如何才能知道可以传什么才不报错呢?加一个判断:
deffunc(obj):ifxnotinobj.__dict__:returnobj.xfunc()
在调用属性之前,先判断一下是否在__dict__中,但是并不是所有的都有__dict__方法的,在python有一种更好的方法判断,这就是反射.
如何实现反射classPeople:def__init__(self,name,age):self.name=nameself.age=agedefsay(self):print(%s---%s%(self.name,self.age))obj=People(李建钢,18)dir查看对象下有哪些属性
如何获取到obj下面有哪些属性和方法呢?python提供了dir函数实现了该功能.
print(dir(obj))
此列表下面的全是字符串,是不能直接调用的.
dir(obj)[-2]#==nameobj.dir(obj)[-2]#obj只能点出name,不能点出name通过字符串发射到真正的属性上,得到属性值
通过__dict__可以访问到属性对应的值.
print(obj.__dict__[name])
和dir结合起来
print(obj.__dict__[dir(obj)[-2]])四个内置函数的使用
但是并不是所有的都有__dict__方法.所以python内置了四个函数提供使用.
hasattr()判断print(hasattr(obj,name))#返回布尔值getattr()获取
print(getattr(obj,name))#返回name的值:李建钢setattr()赋值
print(setattr(obj,name,王大锤))#没有返回值delattr()删除
print(delattr(obj,name))
全部通过字符串来操作.
案例classFtp:defput(self):print(上传功能)defget(self):print(下载功能)definteractive(self):method=input(":").strip()ifhasattr(self,method):getattr(self,method)else:print(指令不存在)obj=Ftp()obj.interactive()内置方法什么是内置方法?
在类内部,以__开头并__结尾的方法.会在某种情况下自动触发.
如何使用内置方法__str__方法
classPeople:def__init__(self,name,age):self.name=nameself.age=agedefsay(self):print(%s---%s%(self.name,self.age))obj=People(李建钢,18)obj1=int(10)print(obj)print(obj1)
自定义类打印的是对象的函数地址,而内置类打印的是10.说明内置类做了一系列的操作.执行print会触发操作,返回10.
classStr:def__init__(self,name,age):self.name=nameself.age=agedef__str__(self):print(打印实例自动触发该功能)obj=Str(wezhon,18)print(obj)
可以看到print(obj)催发了__str__的运行.但是报错了,提示放回了一个非字符串的值,因为__str__没有指定return,所以返回的是None.
__del__方法在清理对象时触发,会先执行该方法:
元类在linux中,一切皆为文件;在Python中,一切皆为对象.
调用类实例化,可以得到一个对象.既然说一切皆为对象,那么class也是对象.生成自定义类的类叫做元类(type).
元类就是实例化产生类的类.元类---(实例化)---类---(实例化)---对象.
使用type()函数可以查看被谁实例化出来的.
可以看到元类为type.
class关键字实例化类的步骤类名class_name="People"#等同于class关键字后接的名字类的基类
class_bases=(object)#等同于类的名字后面()的内容执行类体代码拿到类的名称空间
#类体代码class_dic={}class_body="""def__init__(self,name,age):self.name=nameself.age=agedefsay(self):print(%s-%s%(self.name,self.age))"""#使用exec函数,传入三个参数#1.class_body,传入代码#2.{}全局名称空间#3.将执行后代码所产生的名称空间传入class_dicexec(class_body,{},class_dic)#得到类的名称空间class_dicprint(class_dic)调用元类
#调用type函数生成一个类,赋值给People#传入三个参数,类名,类体代码,名称空间People=type(class_name,class_bases,class_dic)把类赋值People,People只是一个变量名.得到类People,
可以看出类也是一个对象.
如何自定义元类来控制类的产生在上面的第四步,调用type产生一个类.type是一个元类,能不能自己定义一个元类来产生类呢,这样就可以控制产生类的属性.
定义一个元类
classMymeta(type):pass
只有继承了type的类才是元类.
生成一个类,默认的元类为typemetaclass=type,修改为自己定义的元类Mymeta
classPeople(metaclass=Mymeta):def__init__(self,name,age):self.name=nameself.age=agedefsay(self):print(%s:%s%(self.name,self.age))#默认调用的是type#People=type(class_name,class_bases,class_dic)#现在变为调用Mymeta#People=Mymeta(class_name,class_bases,class_dic)#调用Mymeta发生三件事#1.造一个空对象==People#2.调用Mymeta这个类的__init__方法,完成初始化对象的操作#3.返回初始化的对象
现在People这个类就是通过元类Mymeta产生的了,进而通过Mymeta来控制类的产生.
控制元类
classMymeta(type):def__init__(self):#__init__调用时执行print(runing....)
在生成类的时候提示,Myteta的__init__需要一个参数,但是被传入了四个.因为
People=Mymeta(class_name,class_bases,class_dic)
在产生类的时候传入的本就就有三个参数,在加上自身就是四个,所以在__init__还需要三个形参.
可以看到,打印出来的x,y,z分别为:
变量名基类(默认object)名称空间现在,我在元类里加上一个判断,如果产生的类首字母不是大写,将会报错.
继续,添加控制语句,如果产生的类没有说明文档将会报错.如果有说明文档将打印说明文档.__new__方法ok,回到调用Mymeta这里,在调用Mymeta会发生三件事:
造一个空对象==People调用Mymeta这个类的__init__方法,完成初始化对象的操作返回初始化的对象在第一步的时候会通过__new__方法产生空对象.并且在__init__方法之前执行.
classMymeta(type):def__new__(cls,*args,**kwargs):pass
分别打印cls,*args,**kwargs.
cls:元类*args:类名,基类,类的名称空间**kwargs:空字典最后需要返回结果,不然不会触发__init__.
classMymeta(type):def__new__(cls,*args,**kwargs):print(in__new__)#returnsuper().__new__(cls,*args,**kwargs)returntype.__new__(cls,*args,**kwargs)wezhon
最近更新
推荐文章