一、 反射(自省):主要是指程序可以访问、检测和修改它本身状态或行为的一种能力
四个可以实现自省的函数:
1、hasattr(object,name)
object--->对象,name--->字符串
判断object中有没有一个name字符串对应的方法或属性
class AAA: def __init__(self,name,addr): self.name=name self.addr=addr def sale(self): print('----->') p1=AAA('alex','nanjing') print(hasattr(p1,'name')) #True print(hasattr(p1,'sale')) #True print(hasattr(p1,'shugl')) #False
2、getattr(object,name,default=None)
运行object对象所对应的name方法。若指定了default,不存在name时显示default内容,不指定时报错
class AAA: def __init__(self,name,addr): self.name=name self.addr=addr def sale(self): print('----->') p1=AAA('alex','nanjing') print(getattr(p1,'name')) # alex print(getattr(p1,'sale')) #返回sale函数的内存地址 func=getattr(p1,'sale') func() #-----> print(getattr(p1,'shugl','没有这个参数')) #没有这个参数 print(getattr(p1,'shugl')) #报错
3、setattr(object,name,value)
设置object对象的name属性值为value
class AAA: def __init__(self,name,addr): self.name=name self.addr=addr def sale(self): print('----->') p1=AAA('alex','nanjing') setattr(p1,'name','alex1234') print(p1.name) #alex1234 setattr(p1,'age',30) print(p1.__dict__) #{'age':'30','name':'alex','addr':'nanjing'}
给对象设置函数属性
class AAA: def __init__(self,name): self.name=name def sale(self): print('----->') p1=AAA('alex') setattr(p1,'func',lambda x:x+1) print(p1.__dict__) #{'name':'alex','func':<function <almbda> at 0x00BF 17CB>} setattr(p1,'func1',lambda self:self+'-nanjing') print(p1.func(10)) #11 print(p1.func1('alexxxxx')) #alexxxxx-nanjing
4、del (object,name)
删除object对象的name属性
class AAA: def __init__(self,name,addr): self.name=name self.addr=addr def sale(self): print('----->') p1=AAA('alex','nanjing') print(p1.__dict__) #{'name':'alex','addr':'nanjing'} delattr(p1,'name') print(p1.__dict__) #{'addr':'nanjing'}
二、反射的好处
实际项目中,经常是多个程序员一起合作一个项目,使用反射可以帮助程序员之前开发代码互不影响
#程序员1开发代码 class FtpClient: 'ftp客户端,但是没有实现具体功能' def __init__(self,addr): self.addr=addr print('正在连接服务器%s'%(self.addr)) #程序员2开发代码 from ftp_wenjian import FtpClient f1=FtpClient('192.168.10.208') if hasattr(f1,'put'): func=getattr(f1,'put') func() else: print('没有方法put')
三、类内置的attr方法
1. __getattr__
只有在调用的属性不存在时,才会执行__getattr__
class Foo: def __init__(self,y): self.y=y def __getattr__(self,item): print('执行__getattr__') f1=Foo(10) print(f1.y) #10 print(getattr(f1,'y')) #10 f1.ssss #执行__getattr__ print(f1.shug) #执行__getattr__ #None
2. __delattr__
无论要删除的属性是否存在,都会执行__delattr__
但是实际上,属性并没有被删除!!!需要在__delattr__中删除
class Foo: def __init__(self,y): self.y=y def __delattr__(self,item): print('删除操作')
#self.__dict__.pop(item) f1=Foo(10) del f1.y #删除操作 print(f1.__dict__) #{'y':10} del f1.x #删除操作
3. __setattr__
class Foo: x=1 def __init__(self,y,z): self.y=y
self.z=z def __setattr__(self,key,value): #self.key=value #不能这样设置,会进入死循环 print('--->') self.__dict__[key]=value #生成实例时启动__setattr__时,不会将属性自动加到实例的属性字典,所以需要手动加 f1=Foo(10)
#--->
#--->