一.反射
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 类的派生类
1 class Bar(): 2 pass 3 class Foo(Bar): 4 pass 5 obj=Foo() 6 print(Foo.__bases__) #判断是不是继承类 7 print(issubclass(Foo,Bar)) 8 9 10 11 12 (<class '__main__.Bar'>,) 13 True
1.什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
2.python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
hasattr(object,name)
1.文件直接运行,把一个文件当成脚本运行
2.当成模块导入
1 class People: 2 country='China' 3 def __init__(self,name): 4 self.name=name 5 6 p=People('egon') 7 print(p.__dict__) 8 People.country #调的不是字符串 9 #hasattr 10 print('name' in p.__dict__) 11 print(hasattr(p,'name')) 12 print(hasattr(p,'country')) #p.country 13 print(hasattr(People,'country')) #People.country 14 print(hasattr(People,'__init__')) #People.__init__ 15 16 17 {'name': 'egon'} 18 True 19 True 20 True 21 True 22 True
getattr(object,name,default=None)
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 8 p=People('egon') 9 10 11 #getattr 12 res=getattr(p,'country') #res=p.country 13 print(res) 14 15 f=getattr(p,'walk') #t=p.walk 16 print(f) 17 18 f1=getattr(People,'walk') #类的函数属性 19 print(f1) 20 21 f() #绑定方法第一个参数不用传 22 f1(p) #函数不会自动传值 23 24 China 25 <bound method People.walk of <__main__.People object at 0x00000000004D1978>> 26 <function People.walk at 0x00000000004CE2F0> 27 egon is walking 28 egon is walking
1 print(getattr(p,'xxxx','这个属性确实不存在')) #保证程序不会抛出异常 2 #或者是用下面这个 3 4 if hasattr(p,'walk'): 5 func=getattr(p,'walk') 6 func() 7 print('=======>') 8 9 10 11 这个属性确实不存在 12 egon is walking 13 =======> 14 =======>
setattr(x,y,z)
1 p.sex='male' 2 print(p.sex) 3 print(p.__dict__) 4 setattr(p,'age',18) 5 print(p.__dict__) 6 print(p.age) 7 print(getattr(p,'age')) 8 9 10 11 12 male 13 {'sex': 'male', 'name': 'egon'} 14 {'sex': 'male', 'name': 'egon', 'age': 18} 15 18 16 18
delattr(x,y)
1 # print(p.__dict__) 2 # del p.name 3 # print(p.__dict__) 4 print(p.__dict__) 5 delattr(p,'name') 6 print(p.__dict__) 7 8 9 10 11 {'name': 'egon'} 12 {}
3.反射当前模块的属性
this_module=sys.modules[__name__]
import sys x=11 class Foo: pass def s1(): print('s1') def s2(): print('s2') this_module = sys.modules[__name__] #获取当前模块 print(this_module) print(hasattr(this_module,'s1')) print(getattr(this_module,'s2')) print(this_module.s2) print(this_module.s1) <module '__main__' from 路径 True <function s2 at 0x00000000006BE2F0> <function s2 at 0x00000000006BE2F0> <function s1 at 0x00000000006BE268>
4.反射的用途:
1.把字符串映射成可执行过程
2.实现可插拔机制
1 while True: 2 cmd=input('>>:').strip() 3 if not cmd:continue 4 # if cmd in func_dic: 5 # func=func_dic.get(cmd) #hasattr 6 # func() #func=getattr() 7 if hasattr(this_module,cmd): 8 func=getattr(this_module,cmd) 9 func()
1 class FtpClient: 2 'ftp客户端,但是还没有实现具体的功能' 3 def __init__(self,addr): 4 print('正在连接服务器[%s]' %addr) 5 self.addr=addr
1 import ftpclient 2 #from module import FtpClient 3 f1=ftpclient.FtpClient('192.168.1.1') 4 if hasattr(f1,'get'): #有木有get方法 5 func_get=getattr(f1,'get') 6 func_get() 7 else: 8 print('---->不存在此方法') 9 print('处理其他的逻辑') 10 # print(ftpclient) 11 # print(ftpclient.FtpClient) 12 13 14 15 16 正在连接服务器[192.168.1.1] 17 ---->不存在此方法 18 处理其他的逻辑
通过字符串导入模块
1 m=input('请输入你要导入的模块:') 2 m1=__import__(m) 3 print(m1) 4 print(m1.time()) 5 6 #推荐使用方法 7 import importlib 8 t=importlib.import_module('time') 9 print(t.time()) 10 11 12 13 请输入你要导入的模块:time 14 <module 'time' (built-in)> 15 1493021033.3454628
手动加上类型限制,弥补python没有类型限制的不足。
1 class Foo: 2 def __init__(self,name): 3 self.name=name 4 5 def __setattr__(self,key,value): #都是把属性加到字典里的,递归超过最大限制 6 if not isinstance(value,str): 7 raise TypeError('must be str') 8 # print('---setattr---key:%s,value:%s' %(key,value)) 9 #setattr(self,key,value) #self.key=value 递归了,一直再设置属性 #都是把属性加到字典里的,递归超过最大限制 10 self.__dict__[key]=value #使用它 11 12 def __delattr__(self, item): 13 print('---> from delattr') 14 self.__dict__.pop(item) 15 16 f1=Foo('egon') 17 f1.age='18' 18 print(f1.name) 19 print(f1.age) 20 print(f1.__dict__) ## 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值 21 22 f1.__dict__['a']=3 23 del f1.age
print(f1.__dict__) ##字典里还有age
1 class Foo: 2 def __init__(self,x): 3 self.name=x 4 #属性不存在的情况下才会触发 5 def __getattr__(self, item): 6 print('getattr-->%s %s' %(item,type(item))) 7 8 f=Foo('egon') 9 print(f.xxx) 10 11 12 13 getattr-->xxx <class 'str'> 14 None #返回None
5.二次加工标准类型
定制自己的数据类型
定制列表里只加数字
1 class List(list): ##继承内置的数据类型 2 def append(self, p_object): 3 if not isinstance(p_object,int): 4 raise TypeError('must be int')
#self.append(p_object) 作为对比,这个不对的 5 super().append(p_object) #完成真正的append 6 l=List([1,2,3]) 7 print(l) 8 l.append(4) 9 print(l) 10 11 l.insert(0,-1) 12 l.insert(0,'123') 13 print(l) 14 15 16 [1, 2, 3] 17 [1, 2, 3, 4] 18 ['123', -1, 1, 2, 3, 4]
规范提示数据类型:
1 def test(x:int,y:int)->int: 2 return x+y 3 print(test.__annotations__) 4 5 print(test(1,2)) 6 # print(test(1,'3')) 7 8 9 10 11 {'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>} 12 3
1.使用继承的原理二次加工
1 class List(list): 2 def append(self, p_object): 3 if not isinstance(p_object,int): 4 raise TypeError('must be int') 5 #self.append(p_object) 6 super().append(p_object) 7 # def insert(self, index, p_object): 8 # if not isinstance(p_object,int): 9 # raise TypeError('must be int') 10 # #self.append(p_object) 11 # super().insert(index,p_object) 12 l=List([1,2,3]) 13 print(l) 14 l.append(4) 15 # print(l) 16 print(l) 17 l.insert(0,-1) 18 print(l) 19 # l.insert(0,'123') 20 # print(l) 21 22 23 [1, 2, 3] 24 [1, 2, 3, 4] 25 [-1, 1, 2, 3, 4]
2.授权的方式实现定制自己的数据类型
授权:授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。
实现授权的关键点就是覆盖__getattr__方法
1 #不能用继承,来实现open函数的功能 2 # f=open('a.txt','w') 3 # print(f) 4 # f.write('111') 5 import time 6 class Open: 7 def __init__(self,filepath,m='r',encode='utf-8'): 8 self.x=open(filepath,mode=m,encoding=encode) 9 self.filepath=filepath 10 self.mode=m 11 self.encoding=encode 12 def write(self,line): 13 print('f自己的write',line) 14 t=time.strftime('%Y-%m-%d %X') 15 self.x.write('%s %s'%(t,line)) 16 17 f=Open('b.txt','w') 18 print(f) 19 f.write('1111 ') 20 f.write('11111 ') 21 f.write('11111 ') 22 f.write('11111 ')
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('1111 ') # f.write('11111 ') # f.write('11111 ') # f.write('11111 ') f=Open('b.txt','r+') print(f.read) res=f.read() #self.x.read() print(res) print('=-==>',f.read()) f.seek(0) print(f.read()) # f.flush() # f.close() =------> read <class 'str'> <built-in method read of _io.TextIOWrapper object at 0x00000000008EEA68> =------> read <class 'str'> 2017-04-24 17:49:50 1111 2017-04-24 17:49:50 11111 2017-04-24 17:49:50 11111 2017-04-24 17:49:50 11111 =------> read <class 'str'> =-==> =------> seek <class 'str'> =------> read <class 'str'> 2017-04-24 17:49:50 1111 2017-04-24 17:49:50 11111 2017-04-24 17:49:50 11111 2017-04-24 17:49:50 11111
模拟open()打开文件
import time class Open(): def __init__(self,filepath): self.path=filepath self.x=open(filepath,'w+') def write(self,value): t=time.strftime('%Y-%m-%d') self.x.write(t+value) def __getattr__(self, item): if hasattr(self.x,item): return getattr(self.x,item) f=Open('a.txt') f.read() f.seek(0) f.flush()