面向对象2

mac2022-06-30  136

面向对象之反射

参考 :https://www.cnblogs.com/yuliangkaiyue/p/9516427.html

面向对象之内置方法

__setattr__ ,__getattr__,__delattr__

class Foo: x = 1 def __init__(self, y): self.y = y def __setattr__(self, key, value): print('----->setattr') # self.key =value #等同于赋值,不断触发setattr,造成递归循环 self.__dict__[key] = value def __getattr__(self, item): print('------->getattr') print('%s不存在' % item) def __delattr__(self, item): print('-------delete') # del self.item # 同上理 self.__dict__.pop(item) f = Foo(6) print(f.__dict__) f.z f.z =2print(f.__dict__) f.__dict__['a'] = 10 # 直接调用字典赋值并不会触发setattr方法del f.a print(f.__dict__) 执行结果:----->setattr 因为初始化触发了__setattr__方法执行{'y': 6} ------->getattr 属性Z不存在,触发了getattr方法,所以找不到属性才触发z不存在----->setattr {'y': 6, 'z': 2} -------delete {'y': 6, 'z': 2}

item系列

  __setitem__,__getitem__,__delitem__ 在功能上和上边的有些类似,但是又稍有不同。item系列的特点是把类操作弄得像字典一样。

class Foo: def __init__(self, name): self.name = name def __setitem__(self, key, value): print('from setitem') self.__dict__[key]=value def __getitem__(self, item): print('from getitem') print(self.__dict__.get(item)) def __delitem__(self, key): print('from delitem del [key]') self.__dict__.pop(key) def __delattr__(self, item): print('from delattr del .属性') self.__dict__.pop(item) f1=Foo('李四') print(f1.__dict__) f1['age']=18f1['sex']=''print(f1.__dict__) del f1.age del f1['sex'] f1['home']='滨州'print(f1.__dict__) # {'name': '李四'}# from setitem# from setitem# {'name': '李四', 'age': 18, 'sex': ''}# from delattr# from delitem# from setitem# {'name': '李四', 'home': '滨州'}

为类设置输出 __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) # from repr: School(oldboy1,北京)# from str: (oldboy1,北京)# (oldboy1,北京)'''str函数或者print函数--->obj.__str__()repr或者交互式解释器--->obj.__repr__()如果__str__没有被定义,那么就会使用__repr__来代替输出注意:这俩方法的返回值必须是字符串,否则抛出异常'''print(format(s1,'nat')) print(format(s1,'tna')) print(format(s1,'tan')) print(format(s1,'a')) # oldboy1-北京-私立# 私立:oldboy1:北京# 私立/北京/oldboy1# oldboy1-北京-私立

 

  当然也可以在__str__()中调用format方法,以显示想要的效果 

 析构方法  __del__

  析构方法,当对象在内存中被释放时,自动触发执行。

  注:如果产生的对象仅仅只是python程序级别的(用户级),那么无需定义__del__,如果产生的对象的同时还会向操作系统发起系统调用,即一个对象有用户级与内核级两种资源,比如(打开一个文件,创建一个数据库链接),则必须在清除对象的同时回收系统资源,这就用到了__del__。简而言之,操作系统资源要通过代码手动调用管理的,用完就关闭它,用del方式可以防止忘记关闭操作系统资源而出错,也使代码简洁。

class Foo: def __del__(self): print('回收') f1=Foo() del f1 print('------->') #输出结果# 回收# ------->

 

描述符(__get__, __set__, __delete__)

描述符

本质就是一个新式类,在这个类中至少实现了__get__, __set__, __delete__中的一个,这也被称为描述符协议。

  __get__():调用一个属性时触发

  __set__():为一个属性赋值时触发

  __delete__():采用del删除一个属性时触发

作用

描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中)

class Foo: def __get__(self, instance, owner): print('触发get') def __set__(self, instance, value): print('触发set') def __delete__(self, instance): print('触发delete') f1=Foo() f1.name='egon'f1.name del f1.name

 

  但是,这样子并没有触发三个方法的执行

  那如何才会触发执行呢?

#描述符Strclass Str: def __get__(self, instance, owner): print('Str调用') def __set__(self, instance, value): print('Str设置...') def __delete__(self, instance): print('Str删除...') #描述符Intclass Int: def __get__(self, instance, owner): print('Int调用') def __set__(self, instance, value): print('Int设置...') def __delete__(self, instance): print('Int删除...') class People: name=Str() age=Int() def __init__(self,name,age): #nameStr类代理,ageInt类代理, self.name=name self.age=age #何地?:定义成另外一个类的类属性 #何时?:且看下列演示 p1=People('alex',18) #描述符Str的使用p1.name p1.name='egon'del p1.name #描述符Int的使用p1.age p1.age=18del p1.age #我们来瞅瞅到底发生了什么print(p1.__dict__) print(People.__dict__) #补充print(type(p1) == People) #type(obj)其实是查看obj是由哪个类实例化来的print(type(p1).__dict__ == People.__dict__) 执行结果: Str设置... Int设置... Str调用Str设置... Str删除... Int调用Int设置... Int删除... {} {'__module__': '__main__', 'name': <__main__.Str object at 0x0000000A51974438>, 'age': <__main__.Int object at 0x0000000A51ACFC18>, '__init__': <function People.__init__ at 0x0000000A51AD3BF8>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None} TrueTrue

 

注意事项

  一 描述符本身应该定义成新式类,被代理的类也应该是新式类  二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中  三 要严格遵循该优先级,优先级由高到底分别是           1.类属性           2.数据描述符           3.实例属性           4.非数据描述符           5.找不到的属性触发__getattr__()

  

转载于:https://www.cnblogs.com/yuliangkaiyue/p/9570033.html

最新回复(0)