三 __setattr__,__delattr__,__getattr__
__开头的都是内置的,不定义系统都会有。如果自己定义的话,就会覆盖系统内置的,执行自定义的部分(是否有完成设置的语法,有的话完成,没有就设置没成功,返回空字典)。可以通过dir(Foo)查看所有的内置属性。
用法:
三者的用法演示 class Foo: x=1 def __init__(self,y): self.y=y def __getattr__(self, item): print('----> from getattr:你找的属性不存在') def __setattr__(self, key, value): print('----> from setattr') # self.key=value #这就无限递归了,只要一出现设置值的操作,就会触发__init__函数,然后执行__setattr__.无限递归循环。
# self.__dict__[key]=value #应该使用它
def __delattr__(self, item):
print('----> from delattr')
# del self.item #无限递归了
self.__dict__.pop(item) #__setattr__添加/修改属性会触发它的执行 f1=Foo(10) print(f1.__dict__) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值 f1.z=3 print(f1.__dict__) #__delattr__删除属性的时候会触发 f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作 del f1.a print(f1.__dict__) #__getattr__只有在使用点调用属性且属性不存在的时候才会触发 f1.xxxxxx
class Foo: x=1 def __init__(self,y): self.y=y def __setattr__(self, key, value): print('__setattr__执行') # self.key=value self.__dict__[key]=value f1=Foo(10) print(f1.__dict__) f1.z=2 print(f1.__dict__) class Foo: def __getattr__(self, item): print('------------->') # print(Foo.__dict__) print(dir(Foo)) f1=Foo() print(f1.x) #只有在属性不存在时,会自动触发__getattr__ del f1.x #删除属性时会触发_delattr__ f1.y=10 f1.x=3 # 设置属性的时候会触发——setattr———
利用__setattr__自定义把设置的属性都为字符串类型:
class Foo: x=1 def __init__(self,y): self.y=y def __setattr__(self, key, value): print('__setattr__执行',key,value) # self.key=value if type(value) is str: self.__dict__[key]=value.upper()#自定义全部转化为大写 else: print('【%s】不是字符串类型' %value) f1=Foo('alex') print(f1.__dict__) f1.z=2 print(f1.__dict__)
四 二次加工标准类型(包装)
包装:python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法,这就用到了我们刚学的继承/派生知识(其他的标准类型均可以通过下面的方式进行二次加工。
派生:继承原来的基本属性,并且派生出新的属性规则。
#利用继承派生来定制化函数
class List(list): def append(self, p_object): if type(p_object) is str: #定制只能添加为字符串的函数 #self.append(p_object) 无限死循环,解决方法调用父类 super().append(p_object) else: print('只能添加字符串') def show_middle(self): #定制之获取中间的元素的函数。 i=int(len(self)/2) return self[i-1] l1=List('helloworld')#没写实例化函数,继承list的实例化过程。 #相当于在执行:l2=list(hello world) print(l1,type(l1)) print(l1) l1.append('sd') print(l1) print(l1.show_middle())
['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd'] <class '__main__.List'> ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd'] ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd', 'sd'] o
授权:授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。
实现授权的关键点就是覆盖__getattr__方法