python-面向对象进阶
一、isinstance(obj,cls)和issubclass(sub,super)
isinstance(obj,cls)检查obj是否是cls的对象
issubclass(sub,super)检查sub是否是super的派生类
class Bar: pass class Foo(Bar): pass obj =Foo() print(isinstance(obj,Foo))#True print(issubclass(Foo,Bar))#True
二、反射
python面向对象中的反射:通过字符串的形式操作对象相关的属性
通过下面四个函数可以实现,适用于类和对象
hasattr(object,name):判断一个object中有没有name属性或者方法
getatrr(object,name,default=None):获取object中的name属性或方法,设置defult=None时没找到返回None,没设置报错
setattr(x,y,z)修改x中y的值为z,当y不存在时添加y的值为z
delattr(x,y)删除x中的y属性或方法
演示代码:
class BlackMedium: feature='Ugly' def __init__(self,name,addr): self.name=name self.addr=addr def sell_house(self): print('%s 黑中介卖房子啦,傻逼才买呢,但是谁能证明自己不傻逼' %self.name) def rent_house(self): print('%s 黑中介租房子啦,傻逼才租呢' %self.name) b1=BlackMedium('万成置地','回龙观天露园') #检测是否含有某属性 print(hasattr(b1,'name')) print(hasattr(b1,'sell_house')) #获取属性 n=getattr(b1,'name') print(n) func=getattr(b1,'rent_house') func() # getattr(b1,'aaaaaaaa') #报错 print(getattr(b1,'aaaaaaaa','不存在啊')) #设置属性 setattr(b1,'sb',True) setattr(b1,'show_name',lambda self:self.name+'sb') print(b1.__dict__) print(b1.show_name(b1)) #删除属性 delattr(b1,'addr') delattr(b1,'show_name') delattr(b1,'show_name111')#不存在,则报错 print(b1.__dict__) 四个方法的使用演示
python中一切皆对象,也可以对类使用反射
三、二次加工标准类型(包装)
包装:python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法,这就用到了我们刚学的继承/派生知识(其他的标准类型均可以通过下面的方式进行二次加工)
class List(list): #继承list所有的属性,也可以派生出自己新的,比如append和mid def append(self, p_object): ' 派生自己的append:加上类型检查' if not isinstance(p_object,int): raise TypeError('must be int') super().append(p_object) @property def mid(self): '新增自己的属性' index=len(self)//2 return self[index] l=List([1,2,3,4]) print(l) l.append(5) print(l) # l.append('1111111') #报错,必须为int类型 print(l.mid) #其余的方法都继承list的 l.insert(0,-123) print(l) l.clear() print(l) 二次加工标准类型(基于继承实现)
授权:授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。
实现授权的关键点就是覆盖__getattr__方法
授权示范代码一
#_*_coding:utf-8_*_ __author__ = 'Linhaifeng' #我们来加上b模式支持 import time class FileHandle: def __init__(self,filename,mode='r',encoding='utf-8'): if 'b' in mode: self.file=open(filename,mode) else: self.file=open(filename,mode,encoding=encoding) self.filename=filename self.mode=mode self.encoding=encoding def write(self,line): if 'b' in self.mode: if not isinstance(line,bytes): raise TypeError('must be bytes') self.file.write(line) def __getattr__(self, item): return getattr(self.file,item) def __str__(self): if 'b' in self.mode: res="<_io.BufferedReader name='%s'>" %self.filename else: res="<_io.TextIOWrapper name='%s' mode='%s' encoding='%s'>" %(self.filename,self.mode,self.encoding) return res f1=FileHandle('b.txt','wb') # f1.write('你好啊啊啊啊啊') #自定制的write,不用在进行encode转成二进制去写了,简单,大气 f1.write('你好啊'.encode('utf-8')) print(f1) f1.close() 授权示范二
四、_getattribute_
当__getattribute__与__getattr__同时存在,只会执行__getattrbute__,除非__getattribute__在执行过程中抛出异常AttributeError
class Foo: def __init__(self,x): self.x=x def __getattr__(self, item): print('执行的是我') # return self.__dict__[item] def __getattribute__(self, item): print('不管是否存在,我都会执行') raise AttributeError('哈哈') f1=Foo(10) f1.x f1.xxxxxx
五、_str_,_repr_,_format_
定制对象被打印时的输出信息,必须返回一个字符串类型的值! __str__,__repr__
自定制格式化字符串__format__
format_dict={ 'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型 'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址 'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名 } class School: def __init__(self,name,addr,type): self.name=name self.addr=addr self.type=type def __repr__(self): return 'School(%s,%s)' %(self.name,self.addr) def __str__(self): return '(%s,%s)' %(self.name,self.addr) def __format__(self, format_spec): # if format_spec if not format_spec or format_spec not in format_dict: format_spec='nat' fmt=format_dict[format_spec] return fmt.format(obj=self) s1=School('oldboy1','北京','私立') print('from repr: ',repr(s1)) print('from str: ',str(s1)) print(s1) ''' str函数或者print函数--->obj.__str__() repr或者交互式解释器--->obj.__repr__() 如果__str__没有被定义,那么就会使用__repr__来代替输出 注意:这俩方法的返回值必须是字符串,否则抛出异常 ''' print(format(s1,'nat')) print(format(s1,'tna')) print(format(s1,'tan')) print(format(s1,'asfdasdffd'))
六、__del__
析构方法,当对象在内存中被释放时,会自动触发执行。
当程序结束时,python只会回收自己的内存空间,即用户态内存,而操作系统的资源则没有被回收,这就需要我们定制__del__,在对象被删除前向操作系统发起关闭数据库链接的系统调用,回收资源
# class Foo: # def __del__(self): # print('run....') # obj = Foo() #__call__:在对象被调用时会自动触发该方法, class Foo: def __init__(self,x,y): self.x=x self.y=y def __call__(self, *args, **kwargs): print(self,args,kwargs) obj = Foo()
焚膏油以继晷,恒兀兀以穷年。