python编程 基础入门学习笔记八——反射
本节笔记
Python的反射机制
1).hasattr
2).getattr
3).setattr
4).delattr
Python的反射机制
反射定义
反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。
反射的实现
Python面向对象编程中的反射:通过字符串的形式,操作对象相关的属性。
Python中一切皆对象,所以都可以用反射机制。
下面逐一介绍4个可以实现自省的函数(下述方法适用于类和对象——一切皆对象,类本身也是一个对象):
1)hasattr(obj,name)
判断一个对象里面是否有name属性或name方法,返回bool值(有则返回True,没有就返回False)。需要注意的是这里name需要用引号,也就是说需要是一个字符串的形式。
>>> class ClassName(object): name='Lily' def __init__(self): pass def func(self,name): print("I am %s" %name) >>> obj=ClassName() >>> print(hasattr(obj,"bar")) False >>> print(hasattr(obj,"name")) True >>> print(hasattr(obj,"func")) True
2)getattr(obj,name,default=None)
获取对象obj的属性或者方法,若存在,则获取对象obj的属性或者方法的内存地址,若不存在会有异常而报错。
class ClassName(object): name='Lily' def __init__(self): pass def func(self,name): print("I am %s" %name) obj=ClassName() prop=getattr(obj,"name") print(prop) func=getattr(obj,"func") func("Jack") getattr(obj,"bar") #异常,报错
需要注意的是,如果是获取对象的方法,如果需要运行这个方法,在后面添加一对括号及对应参数。
3)setattr(obj,name,values)
给对象的属性赋值,若这个属性不存在,则先创建再赋值;若这个属性已经存在,则覆盖原属性值。
#-*- coding:utf-8 -*- class ClassName(object): name='Lily' def __init__(self): pass def func(self,name): print("I am %s" %name) obj=ClassName() setattr(obj,'sex','Female') #动态装载一个属性 print('sex=',getattr(obj,'sex')) #获取属性值 setattr(obj,'name','David') #name属性在类中已存在 print('name=',getattr(obj,'name')) #覆盖原类中的name属性值
给对象动态装载方法,当在希望给已有类添加一个新的方法,可以用setattr(obj,name,values),
#-*- coding:utf-8 -*- def add_func(self): print("add_func") class ClassName(object): bar='abc' def __init__(self,name): self.name=name def func(self,name): print("I am %s" %self.name) obj=ClassName("Jack") setattr(obj,'add_func',add_func) #动态装载一个方法 obj.add_func(obj) #执行
需要注意的是,若这个方法已经存在,则存在覆盖的风险,所以建议在 setattr 前先进行判断是否方法已经存在,再根据实际情况设计。
4)delattr(obj,name)
删除obj对象名为name的属性。
#-*- coding:utf-8 -*- class ClassName(object): bar='abc' def __init__(self,name): self.name=name def func(self,name): print("I am %s" %self.name) obj=ClassName("Jack") choice=input(">>:").strip() print(hasattr(obj,choice)) #判断一个对象obj里是否有对应的choice字符串的方法 if hasattr(obj,choice): delattr(obj,choice) print(hasattr(obj,choice))
需要注意的是,这里只能删除普通属性name,无法删除静态属性bar。
#-*- coding:utf-8 -*- #Author:'Yang' class BlackMedia(object): feature='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) obj=BlackMedia('易居','闸北') #检查是否含有某属性或方法 print(hasattr(obj,"name")) #属性 print(hasattr(obj,"sell_house")) #方法 #获取属性或方法 n=getattr(obj,"name") #属性 print(n) func=getattr(obj,"rent_house") #方法 func() #设置(动态装载)属性 print(obj.__dict__) #装载前 setattr(obj,'flag',True) setattr(obj,'show_name',lambda self:self.name+'123') print(obj.__dict__) #装载后 print(obj.show_name(obj)) #删除属性 delattr(obj,'addr') delattr(obj,'show_name') print(obj.__dict__)
True True 易居 易居 租房子 {'addr': '闸北', 'name': '易居'} {'show_name': <function <lambda> at 0x005D4C48>, 'addr': '闸北', 'flag': True, 'name': '易居'} 易居123 {'flag': True, 'name': '易居'}
#-*- coding:utf-8 -*- class Foo(object): staticField='old' def __init__(self): self.name='Lily' def func(self): return 'func' @staticmethod def bar(): return 'bar' print(getattr(Foo,'staticField')) func=getattr(Foo,'func') print(Foo.func(Foo)) bar=getattr(Foo,'bar') print(Foo.bar())
#-*- coding:utf-8 -*- import sys def f1(): print("f1") def f2(): return 'f2' this_module=sys.modules[__name__] print(hasattr(this_module,'f1')) print(getattr(this_module,'f1')) m=getattr(this_module,'f2') print(m())
反射机制的好处
实现可插拔机制
可以事先定义好接口,接口在被完善后才会真正执行,从而实现了即插即用。这其实是一种“后期绑定”。也就是说,我们可以事先定义接口把主要的逻辑写好,后期再做接口功能的实现。
举个例子,程序员A定义了一个接口,但是未实现功能
#-*- coding:utf-8 -*- #程序员A编写 class FtpClient(object): '这是程序员A写的ftp客户端框架,暂未实现具体功能' def __init__(self,addr): print('正在连接服务器[%s]' %addr) self.addr=addr
程序员B不想等到A完全实现功能再运行,这时利用反射事先做判断,不管程序员A的功能是否实现,都不影响程序员B继续实现其他逻辑。
#这个是程序员B f1=FtpClient('192.168.1.1') if hasattr(f1,'get'): func_get=getattr(f1,'get') func_get() else: print('没有这个方法') print('处理其他的逻辑')
如果程序员A未完成的功能希望程序员C实现,程序员C也可以在不改变程序员A的代码情况下,利用反射,也可以完成。
#这个是程序员C def get(): return '---get---' f1=FtpClient('192.168.1.1') if hasattr(f1,'get'): func_get=getattr(f1,'get') func_get() else: print('没有这个方法') # print('处理其他的逻辑') print("创建这个方法") setattr(f1,'get',get) print(f1.get())
动态导入模块(基于反射当前模块成员)
#-*- coding:utf-8 -*- import sys def f1(): print("f1") def f2(): return 'f2'
#-*- coding:utf-8 -*- con,action=input("module_addr:").split('/') module=__import__(con) #动态导入模块,等价于import con as module func=getattr(module,action) res=func() #获取模块中函数的返回值 print(res)
输出:
addr:module1/f2 <---这里需要键盘输入
f2
import sys __import__('theModuleFullName') #动态地导入模块 m=sys.modules['theModuleFullName'] #得到这个模块 attstr=dir(m) #得到属性的列表 for str in attstr: #迭代之 att=getattr(m,str) #如果是类,而且是Father的子类 if type(att)==type and issubclass(att,Father): theObj=att() #实例化 theObj.doSomething() #开始调用
浙公网安备 33010602011771号