反射attr以及模块动态导入
一、实现自省的四个函数
1、hasattr判断一个对象中有没有一个name字符串对应的方法或属性
class BlackMedium: feture="Ugly" def __init__(self,name,addr): self.name=name self.addr=addr def sell_house(self): print("%s 正在卖房子,傻逼才买呢" %self.name) def rent_house(self): print("%s 正在租房子,傻逼才租呢" % self.name) b1=BlackMedium("中原地产","北京通州梨园") #b1.name---->b1.__dic__["name"] print(hasattr(b1,"name"))#就是检测实例的属性字典里面有没有name这个key print(hasattr(b1,"sell_house"))#但是b1的属性字典里面没有sell_house,也是True啊 #所以hasattr是检查实例到底能不能调用这个属性,能调用就True C:\python35\python3.exe D:/pyproject/day26/反射.py True True
如果没有则返回False
2、getaddr 获取实例的属性
class BlackMedium: feture="Ugly" def __init__(self,name,addr): self.name=name self.addr=addr def sell_house(self): print("%s 正在卖房子,傻逼才买呢" %self.name) def rent_house(self): print("%s 正在租房子,傻逼才租呢" % self.name) b1=BlackMedium("中原地产","北京通州梨园") print(getattr(b1,"name"))#获取实例的数据属性 print(getattr(b1,"addr"))#获取实例的数据属性 func=getattr(b1,"sell_house")#获取实例的函数属性,赋值给func func() C:\python35\python3.exe D:/pyproject/day26/反射.py 中原地产 北京通州梨园 中原地产 正在卖房子,傻逼才买呢
如果需要获取的实例的属性没有的话就报错了
class BlackMedium: feture="Ugly" def __init__(self,name,addr): self.name=name self.addr=addr def sell_house(self): print("%s 正在卖房子,傻逼才买呢" %self.name) def rent_house(self): print("%s 正在租房子,傻逼才租呢" % self.name) b1=BlackMedium("中原地产","北京通州梨园") print(getattr(b1,"name"))#获取实例的数据属性 print(getattr(b1,"addr"))#获取实例的数据属性 func=getattr(b1,"sell_house11111111111111")#获取实例的函数属性,赋值给func func() AttributeError: 'BlackMedium' object has no attribute 'sell_house11111111111111'
可以加一个默认的参数,如果getaddr获取的属性不存在的话就返回你定义的那个
class BlackMedium: feture="Ugly" def __init__(self,name,addr): self.name=name self.addr=addr def sell_house(self): print("%s 正在卖房子,傻逼才买呢" %self.name) def rent_house(self): print("%s 正在租房子,傻逼才租呢" % self.name) b1=BlackMedium("中原地产","北京通州梨园") print(getattr(b1,"name"))#获取实例的数据属性 print(getattr(b1,"addr"))#获取实例的数据属性 print(getattr(b1,"sell_housesss","1111"))#获取实例的函数属性,赋值给func C:\python35\python3.exe D:/pyproject/day26/反射.py 中原地产 北京通州梨园 1111
3、setaddr给对象(实例)设置属性
class BlackMedium: feture="Ugly" def __init__(self,name,addr): self.name=name self.addr=addr def sell_house(self): print("%s 正在卖房子,傻逼才买呢" %self.name) def rent_house(self): print("%s 正在租房子,傻逼才租呢" % self.name) b1=BlackMedium("中原地产","北京通州梨园") # b1.sb=True setattr(b1,"sb",True)#给b1这个实例增加一个sb的属性,值为True setattr(b1,"加油",111) setattr(b1,"name","大sb")#如果之前有name的属性,会覆盖之前的属性值 print(b1.__dict__)#查看实例b1的属性字典 C:\python35\python3.exe D:/pyproject/day26/反射.py {'name': '大sb', 'sb': True, '加油': 111, 'addr': '北京通州梨园'}
用setaddr给对象(实例)设置函数属性
class BlackMedium: feture="Ugly" def __init__(self,name,addr): self.name=name self.addr=addr def sell_house(self): print("%s 正在卖房子,傻逼才买呢" %self.name) def rent_house(self): print("%s 正在租房子,傻逼才租呢" % self.name) b1=BlackMedium("中原地产","北京通州梨园") setattr(b1,"func",lambda x:x+1) setattr(b1,"func1",lambda self:self.name+"sb") print(b1.__dict__) print(b1.func) print(b1.func(6)) print(b1.func1(b1)) C:\python35\python3.exe D:/pyproject/day26/反射.py {'func1': <function <lambda> at 0x0000000000D32400>, 'func': <function <lambda> at 0x0000000000D321E0>, 'addr': '北京通州梨园', 'name': '中原地产'} <function <lambda> at 0x0000000000D321E0> 7 中原地产sb
4、delattr 删除实例的属性
class BlackMedium: feture="Ugly" def __init__(self,name,addr): self.name=name self.addr=addr def sell_house(self): print("%s 正在卖房子,傻逼才买呢" %self.name) def rent_house(self): print("%s 正在租房子,傻逼才租呢" % self.name) b1=BlackMedium("中原地产","北京通州梨园") # b1.sb=True setattr(b1,"sb",True)#给b1这个实例增加一个sb的属性,值为True setattr(b1,"加油",111) setattr(b1,"name","大sb")#如果之前有name的属性,会覆盖之前的属性值 print(b1.__dict__)#查看实例b1的属性字典 del b1.sb#删除b1的属性 del b1.加油#删除b1的属性 print(b1.__dict__) C:\python35\python3.exe D:/pyproject/day26/反射.py {'sb': True, 'addr': '北京通州梨园', '加油': 111, 'name': '大sb'} {'addr': '北京通州梨园', 'name': '大sb'}
class BlackMedium: feture="Ugly" def __init__(self,name,addr): self.name=name self.addr=addr def sell_house(self): print("%s 正在卖房子,傻逼才买呢" %self.name) def rent_house(self): print("%s 正在租房子,傻逼才租呢" % self.name) b1=BlackMedium("中原地产","北京通州梨园") # b1.sb=True setattr(b1,"sb",True)#给b1这个实例增加一个sb的属性,值为True setattr(b1,"加油",111) setattr(b1,"name","大sb")#如果之前有name的属性,会覆盖之前的属性值 print(b1.__dict__)#查看实例b1的属性字典 # del b1.sb#删除b1的属性 # del b1.加油#删除b1的属性 delattr(b1,"sb") print(b1.__dict__) C:\python35\python3.exe D:/pyproject/day26/反射.py {'sb': True, 'addr': '北京通州梨园', 'name': '大sb', '加油': 111} {'addr': '北京通州梨园', 'name': '大sb', '加油': 111}
上面这四种attr都是在自己这里找,使用它们来实现自省的功能,就是自我反省,自我检查的意思,从自己这里找
5、反射的具体应用
gouguoqi负责开发ftp_client这个类,但是出去旅游去了,代码只写了一半儿 class FtpClient: 'ftp客户端,但是还么有实现具体的功能' def __init__(self,addr): print('正在连接服务器[%s]' %addr) self.addr=addr
miaoye负责一个其他的类,但是跟gouguoqi是一个团队的,虽然ftp_client没有写好,但是很不影响miaoye编写代码
from ftp_client import FtpClient f1=FtpClient('1.1.1.1') # f1.put()#由于人家类还写好,直接调用就报错了 if hasattr(f1,'put'):#所以先判断一下人家到底写好了没有 func_get=getattr(f1,'put') func_get() else: print('其他的逻辑') C:\python35\python3.exe D:/pyproject/day26/miaoye使用者.py 正在连接服务器[1.1.1.1] 正在上传文件
过了半年,gouguoqi度假回来了,写好了ftp_clent这个类,miaoye那里的代码都不用动,直接就可以用了
gouguoqi的ftp_client
class FtpClient: 'ftp客户端,但是还么有实现具体的功能' def __init__(self,addr): print('正在连接服务器[%s]' %addr) self.addr=addr def put(self): print('正在上传文件')
miaoye的
from ftp_client import FtpClient f1=FtpClient('1.1.1.1') # f1.put()#由于人家类还写好,直接调用就报错了 if hasattr(f1,'put'):#所以先判断一下人家到底写好了没有 func_get=getattr(f1,'put') func_get() else: print('其他的逻辑') C:\python35\python3.exe D:/pyproject/day26/miaoye使用者.py 正在连接服务器[1.1.1.1] 正在上传文
这就叫做可插拔式设计
二、动态导入模块
1、__import__导入的只导入到顶级,就是导入了m1,
module_t=__import__("m1.t") print(module_t) C:\python35\python3.exe D:/pyproject/day26/动态模块导入.py <module 'm1' (namespace)> module_t=__import__("m1.t") print(module_t) module_t.t.test1() C:\python35\python3.exe D:/pyproject/day26/动态模块导入.py <module 'm1' (namespace)> test1 m=__import__("test") print(m)
2、补充:
把t模块中的所有的方法都导入过来
t模块中的内容
def test1(): print("test1") def test2(): print("test2") from m1.t import * test1() test2() C:\python35\python3.exe D:/pyproject/day26/动态模块导入.py test1 test2
那我们把t模块中的test2前面加个下划线,变为私有属性之后import *就不能导入了
def test1(): print("test1") def _test2(): print("test2") NameError: name 'test2' is not defined
但是我们可以换种导入的方式,就可以正常导入了
from m1.t import test1,_test2 test1() _test2() C:\python35\python3.exe D:/pyproject/day26/动态模块导入.py test1 test2
3、利用模块的方式 import importlib
这种方式直接就可以导入到t了。而不是下面这样
module_t=__import__("m1.t") print(module_t) module_t.t.test1() import importlib m=importlib.import_module("m1.t") print(m) m.test1() m._test2() C:\python35\python3.exe D:/pyproject/day26/动态模块导入.py <module 'm1.t' from 'D:\\pyproject\\day26\\m1\\t.py'> test1 test2