1 isinstance 和issubclass
instance:判断该对象是否是类的对象
isinstance(obj,Foo)
1 2
| x = [] print(isinstance(x,list))
|
结果:
True
issubclass:判断是否是继承
1 2 3 4 5 6
| class Foo: pass class Bar(Foo): pass print(issubclass(Bar,Foo))
|
结果:
True
通过下面的方式也可以查看
print(Bar.base)
2 反射
反射是Smi首次提出的,主要指程序可以访问、检测和修改它本身状态行为的一种能力,也可以叫做自省
2.1面向对象中的反射
面向对象中的反射,是通过字符串形式操作对象的属性,Python中一切都是对象,都可以使用对象
Python中通过hasattr、getattr、setattr、deltattr实现自省的函数,适用于类和对象(一切都是对象)
反射就是把字符串反射成相应的命令
hasattr
查看类和对象中是否有name,用字符串表示,实例在找的时候首先从自身找,自身没有从类找。
1 2 3 4 5
| class Foo: name = 'aaa' f1 =Foo() print(hasattr(Foo,'name')) print(hasattr(f1,'name'))
|
结果:
True
True
setattr
setattr是设置属性,setattr(x,y,z)
1 2 3 4 5 6 7
| class Foo: name = 'aaa' f1 =Foo() setattr(Foo,'age',18) print(Foo,'age') print(f1,'age')
|
deltattr
1 2 3 4
| print(Foo.__dict__) delattr(Foo,'name') print(Foo.__dict__) print(hasattr(f1,'name'))
|
结果:
False
通过打印类的名称空间可以查看到name已经没有了
getattr
getattr是查找那个属性,并把命名它的值获得,实际的原理是通过获得字典中的key,然后获得value
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class People: country = 'china' def __init__(self,name): self.name=name p = People('aaa') print(hasattr(p,'name')) print('name' in p.__dict__) print(hasattr(p,'country')) print(hasattr(People,'country')) print(getattr(p,'country')) print(getattr(p,'__init__')) print(getattr(People,'country'))
|
2.3模块的反射
Python中一切皆对象,模块文件等都是对象
1 2 3 4 5 6 7 8 9
| import sys def s1(): pass def s2(): pass this_module = sys.modules[__name__] print(hasattr(this_module,'s1')) print(getattr(this_module,'s1'))
|
function s1 at 0x00000000005F3E18
2.4 使用反射的好处
2.4.1 实现可拔插机制
可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,
这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),
然后后期再去实现接口的功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class FtpClient: def __init__(self,addr): print("正在连接服务器%s" % addr) self.addr = addr f1 = FtpClient("192.168.0.1") if hasattr(f1, 'get'): func = getattr(f1, 'get') func() else: print("不存在此方法") print("处理其他逻辑")
|
第一个人的代码只提供了接口,并没有写完,但是第二个人要用第一个人的代码中,通过自省进行判断,后面的人就可以直接拿来用了
2.4.2 动态导入模块
动态导入模块(基于反射当前模块成员)
![http://images2015.cnblogs.com/blog/658994/201705/658994-20170519163027791-265304832.png]
3 内置attr
getattr
getattr只有在调用的属性不存在的时候才会触发
1 2 3 4 5 6 7 8
| class Foo: def __init__(self,name): self.name = name def __getattr__(self, item): print("getattr--%s %s"%(item,type(item))) f = Foo('aaa') print(f.xxx)
|
- 结果:
getattr–xxx class ‘str’
None
setattr
setattr添加/修改属性会触发它的执行
本质是修改的 self.dict[key]
1 2 3 4 5 6 7 8 9
| class Foo: def __init__(self,x): self.name=x def __setattr__(self, key, value): self.__dict__[key]=value f1 = Foo('aaa') f1.x='bbb' f1.age=18 print(f1.__dict__)
|
deltattr
只有删除属性的时候才会触发deltatr的执行
1 2 3 4 5 6 7 8 9 10 11
| class Foo: def __init__(self,x): self.name=x def __setattr__(self, key, value): self.__dict__[key]=value def __delattr__(self, item): self.__dict__.pop(item) f1=Foo('aaa') print(f1.__dict__) del f1.name print(f1.__dict__)
|
结果:
{‘name’: ‘aaa’}
{}
4 反射的应用
4.1 可插拔机制
1 2 3 4 5 6 7 8 9 10 11
| class FtpClient: def __init__(self,addr): print('正在连接服务器[%s]'%addr) self.addr = addr def get(self): print('get') def test(self): print('test')
|
1 2 3 4 5 6 7 8 9
| import ftpclient f1=ftpclient.FtpClient('192.168.1.1') if hasattr(f1,'get'): func_get=getattr(f1,'get') func_get() else: print('其他逻辑')
|
4.2 通过字符串导入模块
1 2 3
| m = input("输入你要导入的模块") m1 = __import__(m) print(m1)
|
1 2 3
| import importlib t = importlib.import_module('time') print(t.time)
|
5 二次加工标准类型(包装)
Python内部已经有了标准的数据类型和内置方法,但是在很多的情况下,我们需要对数据类型进行自己定制,这几用到了继承和派生的知识
对append添加限制,只能添加数字类型的
1 2 3 4 5 6 7 8 9
| class List(list): def append(self, p_object): if not isinstance(p_object,int): raise TypeError('must be int') super().append(p_object) l = list([1,2,3]) print(l) l.append(4) print(l)
|
结果:
[1, 2, 3]
[1, 2, 3, 4]
上面的情况仅仅是对append进行了修改并添加了限制,list的其他的属性如insert是没有限制的
授权
授权是包装的一个特性,上面的情况是通过继承来实现的,但是函数是不能继承的
授权的过程是所有更新的功能都是由新类的某部分来处理,已经存在的就授权给对象的默认属性
实现授权的关键点就是覆盖getattr方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import time class Open: def __init__(self,filepath,mode='r',encoding='utf-8'): self.x = open(filepath,mode=mode,encoding=encoding) self.filepath=filepath self.mode=mode self.encoding=encoding def write(self,line): t=time.strftime('%Y-%m-%d %X') self.x.write("%s %s" %(t,line)) def __getattr__(self, item): return getattr(self.x,item) f=Open('b.txt','w') f.write('123\n') f.write('123\n') f.write('123\n') f.write('123\n') f.write('123\n') f.write('123\n') f.write('123\n')
|
这样就能在文件中添加了带有时间的内容
对文件进行读操作:
1 2 3 4 5
| f=Open('b.txt','r') res = f.read() print(res) f.seek(0) print(f.read())
|