反射及attr使用
反射及attr使用
isinstance(obj,cls):检查是否obj是否是类cls的对象。
class Foo(object): pass obj = Foo() isinstance(obj,Foo)
issubclass(sub,super):检查sub类是否是super类的派生类。
class Foo(object): pass class Bar(Foo): pass issubclass(Bar,Foo)
反射
反射是指程序可以访问、检测和修改它本身状态或行为的一种能力,也叫自省。
在python面向对象中的反射,通过字符串的形式操作对象相关的属性,python中的一切事物都是对象(都可以使用反射)。
四个可以实现自省的函数:这四个函数适用于类和对象(一切皆为对象,类本身也是一个对象)
四个函数分别是:hasattr、getattr、setattr、delattr。
attr方法
hasattr:判断是否有要查询的属性的名字。
class People: country='China' def __init__(self,name): self.name=name # def walk(self): # print('%s is walking' %self.name) p=People('egon') # People.country #类.数据属性 # print(People.__dict__) # print(p.name) #通过实例化.函数属性的方式,调用name函数属性。 # print(p.__dict__) #### 反射是通过字符串来访问到country属性 #### hasattr print('name' in p.__dict__) print(hasattr(p,'name')) print(hasattr(p,'name1213')) print(hasattr(p,'country')) #p.country print(hasattr(People,'country')) #People.country print(hasattr(People,'__init__')) #People.__init__
getattr:拿到要查询的属性的结果,并返回。getattr需要返回值。
class People: country='China' def __init__(self,name): self.name=name def walk(self): print('%s is walking' %self.name) ##### getattr p=People('egon') res=getattr(p,'country') #res=p.country print(res) f=getattr(p,'walk') #t=p.walk print(f) f1=getattr(People,'walk') print(f1) f() #f()是walk的绑定方法,不需要传值。 f1(p) #f1是一个函数,所以要传值。所以把p传进去。 print(getattr(p,'country','这个属性确实不存在')) #如果有country,那么'这个属性确实不存在'不打印。 print(getattr(p,'xxxxxxxx','这个属性确实不存在')) if hasattr(p,'walk'): func=getattr(p,'walk') func()
setattr:设置
class People: country='China' def __init__(self,name): self.name=name def walk(self): print('%s is walking' %self.name) ##### setattr p=People('egon') p.sex='male' print(p.sex) print(p.__dict__) setattr(p,'age',18) print(p.__dict__) print(p.age) print(getattr(p,'age'))
delattr :删除
class People: country='China' def __init__(self,name): self.name=name def walk(self): print('%s is walking' %self.name) ###### delattr p=People('egon') print(p.__dict__) del p.name print(p.__dict__) print(p.__dict__) delattr(p,'name') print(p.__dict__)
hasattr和getattr的应用:
import sys def add(): print('add') def change(): print('change') def search(): print('search') def delete(): print('delete') func_dic={ 'add':add, 'change':change, 'search':search, 'delete':delete } while True: dic_key = func_dic.keys() print(list(dic_key)) cmd=input('>>:').strip() if not cmd:continue if cmd in func_dic: #hasattr() func=func_dic.get(cmd) #func=getattr() func() #####用反射实现 this_module=sys.modules[__name__] while True: dic_key = func_dic.keys() print(list(dic_key)) cmd=input('>>:').strip() if not cmd:continue if hasattr(this_module,cmd): func=getattr(this_module,cmd) func()
用反射的好处:
一、实现可插拔机制。
有两个程序员,一个jack,一个george,jack在写程序的时候需要用到george所写的类,但是george去跟女朋友度蜜月去了,还没有完成他写的类,jack想到了反射,使用了反射机制,jack可以继续完成自己的代码,等george度蜜月回来后再继续完成类的定义并且去实现jack想要的功能。
反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用。这其实是一种“后期绑定”,即可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能。
george还没实现全部功能:client端
class FtpClient: "ftp客户端,但是还没有实现具体的功能" def __init__(self,addr): print("正在连接服务器[%s]" %addr) self.addr = addr def test(self): print("test") def get(self): print("get----》")
不影响jack的代码编写:server端
#from module import FtpClient f1=FtpClient("192,168,1,1") if hasattr(f1,"get") func_get = getattr(f1,"get") func_get() else: print("----》不存在此方法") print("处理其他的逻辑")
二、动态导入模块(基于反射当前模块成员)
importlib的使用,通过字符串导入模块:
# m=input("请输入你要导入的模块:") # m1=__import__(m) # print(m1) # print(m1.time()) #推荐使用方法 import importlib t=importlib.import_module('time') print(t.time())
__setattr__:在为对象设置属性的时候,就会被触发运行。
__delattr__:在del的时候,用pop进行删除
#####__setattr__,__getattr__,__delattr__, class Foo: def __init__(self,x): self.name=x # def __setattr__(self, key, value): #为对象设置属性时,会触发setattr的运行 if not isinstance(value,str): #对value的数据类型限制 raise TypeError('must be str') print('----setattr---key:%s,value:%s' %(key,value)) # print(type(key)) # print(type(value)) # self.key=value # setattr(self,key_str,value) #self.key_attribute=value self.__dict__[key]=value def __delattr__(self, item): print('delattr:%s' %item) print(type(item)) # delattr(self,item) # del self.item self.__dict__.pop(item) f1=Foo('egon') #f1.name='egon' f1.age="18" print(f1.__dict__) print(f1.name) print(f1.age) print(f1.__dict__) # del f1.age # print(f1.__dict__) # print(f1.age)
__getattr__:获取一个指令,当获取的属性不存在的时候,才会触发__getattr__。
class Foo: def __init__(self,x): self.name=x #属性不存在的情况下才会触发 def __getattr__(self, item): print('getattr-->%s %s' %(item,type(item))) f=Foo('egon') # print(f.name) print(f.xxxxxxx)
定制自己的数据类型:也叫二次加工标准类型。
基于继承的原理,来定制自己的数据类型(继承标准类型)
例如:用List定义自己的类型,继承list类,使其在append操作的时候,只能append数字int类型以及insert数字int类型。
class List(list): #List类继承list类的方法。 def append(self, p_object): #定义append方法,已覆盖list的append,p_object是List的append的值 print('--->',p_object) #打印的p_object是即将要被append进List的数据,但是这是打印List列表,不会看到p_object,因为还没有被写进List。 if not isinstance(p_object,int): #加类型判断,如不是int类型,返回异常。 raise TypeError('must be int') super().append(p_object) #用super方法调用父类的list的append功能。将p_object写进List。 def insert(self, index, p_object): #对插入操作也可以更改 if not isinstance(p_object,int): raise TypeError('must be int') super().insert(index,p_object) l=List([1,2,3]) print(l) l.append(4) print(l) l.append('5') print(l) l.insert(0,-1) print(l) l.insert(0,'-1123123213') print(l)
不用继承实现文件读写操作的函数功能:open
不能用继承,来实现open函数的功能 f=open('a.txt','w') print(f) f.write('1111111')
授权的方式实现定制自己的数据类型:
import time class Open: #定义open类 def __init__(self,filepath,m='r',encode='utf-8'): #init要默认生成两个参数,一个是文件路径,一个是文件读取方式。 self.x=open(filepath,mode=m,encoding=encode) #在init里用open,这样在Open类中,没有继承open函数。并且这个x.open才是真正被用到的 self.filepath=filepath #文件路径 self.mode=m #文件模式 self.encoding=encode def write(self,line): #文件句柄的.write操作, print('f自己的write',line) #这里并没有完成真正的write操作。 t=time.strftime('%Y-%m-%d %X') #时间,记录写入的时间。 print(t) self.x.write('%s %s' %(t,line)) #这里用self.x.write才是真正的完成write操作。 def __getattr__(self,item): #用getattr获取init里x.open的各种方法,当Open类中没有read方法的时候,可以用getattr的方式获取到read的方法。 # print('=------>',item,type(item)) #用item解决出现异常的现象,这样写不会出现异常 return getattr(self.x,item) #getattr通过字符串去对象里面找数据 f=Open('b.txt','w') print(f) f.write('111111\n') f.write('111111\n') f.write('111111\n') f=Open('b.txt','r+') # print(f.write) print(f.read) res=f.read() #self.x.read() print(res) print('=-=====>',f.read()) f.seek(0) print(f.read()) # f.flush() # f.close()
-------- END --------