Python之面向对象反射
Python之面向对象反射
isinstance(obj,cls)检查是否obj是否是类 cls 的对象
1 class Foo(object): 2 pass 3 4 obj = Foo() 5 6 isinstance(obj, Foo)
issubclass(sub, super)检查sub类是否是 super 类的派生类
class Foo(object): pass class Bar(Foo): pass issubclass(Bar, Foo)
反射:
1 什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
hasattr(object,name)
判断object中有没有一个name字符串对应的方法或属性
1 def getattr(object, name, default=None): # known special case of getattr 2 """ 3 getattr(object, name[, default]) -> value 4 5 Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y. 6 When a default argument is given, it is returned when the attribute doesn't 7 exist; without it, an exception is raised in that case. 8 """ 9 pass
1 def setattr(x, y, v): # real signature unknown; restored from __doc__ 2 """ 3 Sets the named attribute on the given object to the specified value. 4 5 setattr(x, 'y', v) is equivalent to ``x.y = v'' 6 """ 7 pass
1 def delattr(x, y): # real signature unknown; restored from __doc__ 2 """ 3 Deletes the named attribute from the given object. 4 5 delattr(x, 'y') is equivalent to ``del x.y'' 6 """ 7 pass
1 class BlackMedium: 2 feature='Ugly' 3 def __init__(self,name,addr): 4 self.name=name 5 self.addr=addr 6 7 def sell_house(self): 8 print('%s 黑中介卖房子啦,傻逼才买呢,但是谁能证明自己不傻逼' %self.name) 9 def rent_house(self): 10 print('%s 黑中介租房子啦,傻逼才租呢' %self.name) 11 12 b1=BlackMedium('万成置地','回龙观天露园') 13 14 #检测是否含有某属性 15 print(hasattr(b1,'name')) 16 print(hasattr(b1,'sell_house')) 17 18 #获取属性 19 n=getattr(b1,'name') 20 print(n) 21 func=getattr(b1,'rent_house') 22 func() 23 24 # getattr(b1,'aaaaaaaa') #报错 25 print(getattr(b1,'aaaaaaaa','不存在啊')) 26 27 #设置属性 28 setattr(b1,'sb',True) 29 setattr(b1,'show_name',lambda self:self.name+'sb') 30 print(b1.__dict__) 31 print(b1.show_name(b1)) 32 33 #删除属性 34 delattr(b1,'addr') 35 delattr(b1,'show_name') 36 delattr(b1,'show_name111')#不存在,则报错 37 38 print(b1.__dict__)
1 class Foo(object): 2 3 staticField = "old boy" 4 5 def __init__(self): 6 self.name = 'wupeiqi' 7 8 def func(self): 9 return 'func' 10 11 @staticmethod 12 def bar(): 13 return 'bar' 14 15 print getattr(Foo, 'staticField') 16 print getattr(Foo, 'func') 17 print getattr(Foo, 'bar')
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import sys 5 6 7 def s1(): 8 print 's1' 9 10 11 def s2(): 12 print 's2' 13 14 15 this_module = sys.modules[__name__] 16 17 hasattr(this_module, 's1') 18 getattr(this_module, 's2')
导入其他模块,利用反射查找该模块是否存在某个方法
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 def test(): 5 print('from the test')
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 """ 5 程序目录: 6 module_test.py 7 index.py 8 9 当前文件: 10 index.py 11 """ 12 13 import module_test as obj 14 15 #obj.test() 16 17 print(hasattr(obj,'test')) 18 19 getattr(obj,'test')()
1 class People: 2 country='China' 3 def __init__(self,name): 4 self.name=name 5 # def walk(self): 6 # print('%s is walking' %self.name) 7 p=People('egon') 8 # 9 # People.country 10 # print(People.__dict__) 11 12 # print(p.name) 13 # print(p.__dict__) 14 15 # p.name 16 17 18 #hasattr 19 # print('name' in p.__dict__) 20 # print(hasattr(p,'name')) 21 # print(hasattr(p,'name1213')) 22 23 # print(hasattr(p,'country')) #p.country 24 # print(hasattr(People,'country')) #People.country 25 # print(hasattr(People,'__init__')) #People.__init__ 26 27 28 #getattr 29 # res=getattr(p,'country') #res=p.country 30 # print(res) 31 # 32 # f=getattr(p,'walk') #t=p.walk 33 # print(f) 34 # 35 # f1=getattr(People,'walk') 36 # print(f1) 37 # 38 # f() 39 # f1(p) 40 41 42 # print(p.xxxxxxx) 43 # print(getattr(p,'xxxxxxxx','这个属性确实不存在')) 44 45 # 46 # if hasattr(p,'walk'): 47 # func=getattr(p,'walk') 48 # func() 49 # 50 # print('================>') 51 # print('================>') 52 53 54 #setattr 55 56 # p.sex='male' 57 # print(p.sex) 58 # print(p.__dict__) 59 60 # setattr(p,'age',18) 61 # print(p.__dict__) 62 # print(p.age) 63 # print(getattr(p,'age')) 64 65 66 67 68 #delattr 69 # print(p.__dict__) 70 # del p.name 71 # print(p.__dict__) 72 73 print(p.__dict__) 74 delattr(p,'name') 75 print(p.__dict__)
3 为什么用反射之反射的好处
好处一:实现可插拔机制
有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类,但是egon去跟女朋友度蜜月去了,还没有完成他写的类,lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。
总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能
1 class FtpClient: 2 'ftp客户端,但是还么有实现具体的功能' 3 def __init__(self,addr): 4 print('正在连接服务器[%s]' %addr) 5 self.addr=addr
1 #from module import FtpClient 2 f1=FtpClient('192.168.1.1') 3 if hasattr(f1,'get'): 4 func_get=getattr(f1,'get') 5 func_get() 6 else: 7 print('---->不存在此方法') 8 print('处理其他的逻辑')
好处二:动态导入模块(基于反射当前模块成员)
反射的用途:
import sys def add(): print('add') def change(): print('change') def search(): print('search') def delete(): print('delete') this_module=sys.modules[__name__] while True: cmd=input('>>:').strip() if not cmd:continue if hasattr(this_module,cmd): func=getattr(this_module,cmd) func() # if cmd in func_dic: #hasattr() # func=func_dic.get(cmd) #func=getattr() # func() # func_dic={ # 'add':add, # 'change':change, # 'search':search, # 'delete':delete # } # while True: # cmd=input('>>:').strip() # if not cmd:continue # if cmd in func_dic: #hasattr() # func=func_dic.get(cmd) #func=getattr() # func() # class Foo: # x=1 # def __init__(self,name): # self.name=name # def walk(self): # print('walking......') # f=Foo('egon') # Foo.__dict__={'x':1,'walk':....} # 'x' in Foo.__dict__ #hasattr(Foo,'x') # Foo.__dict__['x'] #getattr(Foo,'x') # print(Foo.x) #'x' in Foo.__dict__
反射实现可插拔机制:
FTP Server:
1 import ftpclient 2 # 3 # print(ftpclient) 4 # print(ftpclient.FtpClient) 5 # obj=ftpclient.FtpClient('192.168.1.3') 6 # 7 # print(obj) 8 # obj.test() 9 10 11 12 # 13 f1=ftpclient.FtpClient('192.168.1.1') 14 if hasattr(f1,'get'): 15 func=getattr(f1,'get') 16 func() 17 else: 18 print('其他逻辑')
FTP Client:
1 class FtpClient: 2 'ftp客户端,但是还么有实现具体的功能' 3 def __init__(self,addr): 4 print('正在连接服务器[%s]' %addr) 5 self.addr=addr 6 def test(self): 7 print('test') 8 9 def get(self): 10 print('get------->')
通过字符串导入模块:
# m=input("请输入你要导入的模块:") # m1=__import__(m) #官方不推荐 # print(m1) #官方不推荐 # print(m1.time()) #官方不推荐 #官方推荐使用方法 import importlib t=importlib.import_module('time') print(t.time())
attr系列:
__getattr__、__setattr__、__delattr__
setattr:为对象设置属性的时候回触发setattr的运行。
getattr:只有在使用点调用属性且属性不存在的时候才会触发
1 class Foo: 2 x=1 3 def __init__(self,y): 4 self.y=y 5 6 def __getattr__(self, item): 7 print('----> from getattr:你找的属性不存在') 8 9 10 def __setattr__(self, key, value): 11 print('----> from setattr') 12 # self.key=value #这就无限递归了,你好好想想 13 # self.__dict__[key]=value #应该使用它 14 15 def __delattr__(self, item): 16 print('----> from delattr') 17 # del self.item #无限递归了 18 self.__dict__.pop(item) 19 20 #__setattr__添加/修改属性会触发它的执行 21 f1=Foo(10) 22 print(f1.__dict__) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值 23 f1.z=3 24 print(f1.__dict__) 25 26 #__delattr__删除属性的时候会触发 27 f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作 28 del f1.a 29 print(f1.__dict__) 30 31 #__getattr__只有在使用点调用属性且属性不存在的时候才会触发 32 f1.xxxxxx
定制自己的数据类型:
# l=list([1,2,3]) # # l.append(4) # l.append('5') # print(l) # class List(list): # pass # # l1=List([1,2,3]) # print(l1) # l1.append(4) # print(l1) # l1.append('5') # print(l1) #基于继承的原理,来定制自己的数据类型(继承标准类型) # class List(list): # def append(self, p_object): # # print('--->',p_object) # if not isinstance(p_object,int): # raise TypeError('must be int') # # self.append(p_object) # super().append(p_object) # def insert(self, index, p_object): # if not isinstance(p_object,int): # raise TypeError('must be int') # # self.append(p_object) # 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) # l.insert(0,'-1123123213') # print(l) # def test(x:int,y:int)->int: # return x+y # print(test.__annotations__) # # print(test(1,2)) # print(test(1,'3')) # # def test(x,y): # return x+y #不能用继承,来实现open函数的功能 # f=open('a.txt','w') # print(f) # f.write('1111111') #授权的方式实现定制自己的数据类型 import time class Open: def __init__(self,filepath,m='r',encode='utf-8'): self.x=open(filepath,mode=m,encoding=encode) self.filepath=filepath self.mode=m self.encoding=encode def write(self,line): print('f自己的write',line) t=time.strftime('%Y-%m-%d %X') self.x.write('%s %s' %(t,line)) def __getattr__(self, item): # print('=------>',item,type(item)) return getattr(self.x,item) # # 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()
作业:
1 #基于继承来定制自己的数据类型 2 class List(list): #继承list所有的属性,也可以派生出自己新的,比如append和mid 3 def append(self, p_object): 4 ' 派生自己的append:加上类型检查' 5 if not isinstance(p_object,int): 6 raise TypeError('must be int') 7 super().append(p_object) 8 # 9 @property 10 def mid(self): 11 '新增自己的属性' 12 index=len(self)//2 13 return self[index] 14 15 16 # l=List([1,2,3]) 17 18 # print(l.mid) 19 20 #基于授权来定制自己的数据类型: 21 22 # class Open: 23 # def __init__(self,filepath,mode,encode='utf-8'): 24 # self.f=open(filepath,mode=mode,encoding=encode) 25 # self.filepath=filepath 26 # self.mode=mode 27 # self.encoding=encode 28 29 # def write(self,line): 30 # print('write') 31 # self.f.write(line) 32 33 # def __getattr__(self, item): 34 # return getattr(self.f,item) 35 36 # # f=Open('a.txt','w') 37 # # f.write('123123123123123\n') 38 # # print(f.seek) 39 # # f.close() 40 # # 41 # # f.write('111111\n') 42 43 44 # f=open('b.txt','w') 45 # f.write('bbbbbb\n') 46 # f.close() 47 # print(f) 48 49 50 51 # class Foo: 52 # def test(self): 53 # pass 54 # 55 # print(getattr(Foo,'test')) 56 # 57 # obj=Foo() 58 # print(getattr(obj,'test')) 59 60 61 62 class List: 63 def __init__(self,x): 64 self.seq=list(x) 65 66 def append(self,value): 67 if not isinstance(value,str): 68 raise TypeError('must be str') 69 self.seq.append(value) 70 @property 71 def mid(self): 72 index=len(self.seq)//2 73 return self.seq[index] 74 def __getattr__(self, item): 75 return getattr(self.seq,item) 76 77 def __str__(self): 78 return str(self.seq) 79 80 l=List([1,2,3]) 81 82 l.append('1') 83 84 print(l.mid) 85 l.insert(0,123123123123123123123123123) 86 # print(l.seq) 87 88 print(l) 89 90 91 obj.name='egon' 92 del obj.name