python基础之反射、面向对象进阶
isinstance(obj,cls)和issubclass(sub,super)
isinstance(obj,cls)检查是否obj是否是类 cls 的对象,如果是返回True
1 class Foo(object): 2 pass 3 obj = Foo() 4 print(isinstance(obj, Foo))
issubclass(sub, super)检查sub类是否是 super 类的派生类,如果是返回True
1 class Foo(object): 2 pass 3 class Bar(Foo): 4 pass 5 issubclass(Bar, Foo)
反射
反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。
python面向对象中的反射:通过字符串的形式操作对象相关的属性。而python中的一切事物都是对象,即都可以使用反射。
示例代码:
1 class Teacher: 2 school='jialidun' 3 def __init__(self,name,age): 4 self.name=name 5 self.age=age 6 def teach(self): 7 print('%s teach' %self.name)
通过字符串的方式判断是否存在一个属性:
1 t=Teacher('bob',18) 2 print(hasattr(Teacher,'name')) #False 3 print(hasattr(Teacher,'school')) #True 4 print(hasattr(Teacher,'teach')) #True 5 print(hasattr(t,'name')) #True 6 print(hasattr(t,'school')) #True 7 print(hasattr(t,'teach')) #True
通过字符串的方式获取一个属性:
1 print(getattr(Teacher,'school')) #获取到则返回属性的值 2 print(getattr(Teacher,'sdfad',None)) #获取不到返回None,如果不指定None那么抛出异常错误
通过字符串的方式设定一个属性:
1 setattr(Teacher,'sex','male') #设定Teacher类的属性sex='male' 2 setattr(t,'sex','female') #设定对象t对象的属性sex='female' 3 print(Teacher.__dict__) 4 print(t.__dict__)
通过字符串的方式删除一个属性:
1 delattr(Teacher,'sex') 2 delattr(t,'sex')
反射应用场景:用户交互
1 class Cmd: 2 def __init__(self,name): 3 self.name=name 4 def run(self): 5 while True: 6 cmd=input('>>>').strip() 7 if not cmd:continue 8 if hasattr(self,cmd): #判断这个类包含不包含输入的属性 9 func=getattr(self,cmd) #如果包含,获取该属性 10 func() #执行该属性(输入name会抛错提示字符串不能被调用,因为name是一个数据属性,而非函数属性) 11 else: 12 print('not valid func') 13 def ls(self): 14 print('ls function') 15 def pwd(self): 16 print('pwd function') 17 def cat(self): 18 print('cat function') 19 c=Cmd('bob') 20 c.run()
反射的好处
实现可插拔机制:可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,即可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能
动态导入模块:基于反射当前模块成员
__str__方法
改变对象的字符串显示
1 class Teacher: 2 def __init__(self,name,age): 3 self.name=name 4 self.age=age 5 t=Teacher('bob',18) 6 print(t) 7 输出结果 8 <__main__.Teacher object at 0x0000020FC4DA9278> 9 10 #########分割线君########### 11 12 class Teacher: 13 def __init__(self,name,age): 14 self.name=name 15 self.age=age 16 def __str__(self): 17 return '<name:%s age:%s>' % (self.name, self.age) 18 t=Teacher('bob',18) 19 print(t) #t.__str__() 20 输出结果:类中的__str__函数的执行结果 21 <name:bob age:18>
__del__方法
在程序执行完了之后会自动执行的内容
1 class Foo: 2 def __init__(self,x): 3 self.x=x 4 def __del__(self): 5 print('执行__del__') 6 '''一般用来做一些关于对象执行完了之后剩下的垃圾的清理操作''' 7 f=Foo(10) 8 print('执行完了') 9 10 输出结果:先执行最后的print,没有代码了执行__del__函数 11 执行完了 12 执行__del__
删除对象后立即执行的内容
1 class Foo: 2 def __init__(self,x): 3 self.x=x 4 def __del__(self): 5 print('执行__del__') 6 '''做一些关于对象的清理操作''' 7 f=Foo(10) 8 del f #删除的时候也会执行del内容 9 print('执行完了') 10 11 输出结果:删除了f对象后执行了__del__后才执行最后的print 12 执行__del__ 13 执行完了
item系列
以中括号的方式进行处理类似于:
1 l=['a','b','c'] 2 dic={'a':1} 3 print(l[1]) 4 print(dic['a'])
__getitem__、__setitem__、__delitem__
1 class Teacher: 2 def __init__(self,name,age,sex): 3 self.name=name 4 self.age=age 5 self.sex=sex 6 def __getitem__(self, item): #查询 7 # return getattr(self,item) 8 return self.__dict__[item] 9 def __setitem__(self, key, value): #设置 10 # setattr(self,key,value) 11 self.__dict__[key]=value 12 def __delitem__(self, key): #删除 13 # delattr(self,key) 14 self.__dict__.pop(key) 15 f=Teacher('bob',18,'male') 16 print(f.name) #f['name'] 17 print(f['name']) #查询 18 f['name']='bob_nb' #设置 19 print(f.__dict__) 20 del f['name'] #删除 21 print(f.__dict__)
__len__方法
给对象提供len()统计方法
1 class Teacher: 2 def __init__(self,name,age,sex): 3 self.name=name 4 self.age=age 5 self.sex=sex 6 def __len__(self): #长度设置为10 7 return 10 8 f=Teacher('bob',18,'male') 9 print(len(f)) #输出10
其他方法(补充)
__setattr__,__delattr__,__getattr__方法
1 class Foo: 2 x=1 3 def __init__(self,y): 4 self.y=y 5 def __getattr__(self, item): 6 print('----> from getattr:你找的属性不存在') 7 def __setattr__(self, key, value): #限制赋值,无法对属性直接赋值,必须要对__dict__进行操作赋值 8 print('----> from setattr') 9 # self.key=value #这就无限递归了,任何赋值操作都会调用__setattr__的运行,所以.... 10 # self.__dict__[key]=value #应该使用这种方式,操作字典可以赋值成功 11 def __delattr__(self, item): 12 print('----> from delattr') 13 # del self.item #无限递归了,同__setattr__方法的无限递归 14 self.__dict__.pop(item) 15 #__setattr__添加/修改属性会触发它的执行 16 f1=Foo(10) 17 f1.__setattr__('a',1) #不是直接操作字典,无法赋值 18 print(f1.__dict__) # 因为重写了__setattr__,凡是赋值操作都会触发它的运行,什么都不写,就是根本没赋值,除非直接操作属性字典,否则永远无法赋值 19 f1.z=3 20 print(f1.__dict__) 21 #__delattr__删除属性的时候会触发 22 f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作 23 del f1.a #删除的时候如果上面函数是del self.item,会无限递归 24 print(f1.__dict__) 25 26 #__getattr__只有在使用点调用属性且属性不存在的时候才会触发 27 f1.xxxxxx
包装(对标准数据类型进行方法修改)
通过继承和派生的方式,进行修改源生数据类型的方法
1 class List(list): #继承list所有的属性,也可以派生出自己新的,比如append和mid 2 def append(self, p_object): 3 '派生自己的append:加上类型检查' 4 if not isinstance(p_object,int): 5 raise TypeError('must be int') 6 super().append(p_object) 7 @property 8 def mid(self): 9 '新增自己的属性' 10 index=len(self)//2 11 return self[index]