第十六节:内置函数补充
通过 . 的方式访问、设置、删除对象属性的时候会触发类的内置属性__getattr__、__setattr__、__delattr__
class Dog: def __init__(self,name,age): self.name=name self.age=age def __getattr__(self, item):#在获取不存在的函数属性的时候会触发 print("执行的是getattr") def __setattr__(self, key, value):#在设置对象属性的时候会触发 self.__dict__[key] = value def __delattr__(self, item):#在删除对象属性的时候会触发的内置函数 self.__dict__.pop(item) def run(self): print("%s今年%s"%(name,age) def __getattribute__(self, item): #获取存在的函数属性的时候执行该函数 raise AttributeError('抛出异常')#在获取不存在的函数属性的时候会抛出异常给__getattr__
通过键值的方式访问、设置、删除对象属性的时候会触发类的内置属性__getitem__、__setitem__、__delitem__
class Foo: def __getitem__(self, item): print('getitem') return self.__dict__[item] def __setitem__(self, key, value): print('setitem') self.__dict__[key]=value def __delitem__(self, key): print('delitem') self.__dict__.pop(key) f1=Foo() print(f1.__dict__) f1['name']='sss' print(f1['name']) del f1['name'] 执行结果如下: {} setitem getitem sss delitem
类的内置属性__str__和__repr__:
print函数在执行的时候实际上就是在调用str()函数 在打印对象的时候实际上是在调用内置函数 str()函数 就等于 f1.__str__() class Foo: def __init__(self,name,age): self.name=name self.age=age def __str__(self): return '名字是%s 年龄是%s' %(self.name,self.age) # # f1=Foo('egon',18) # print(f1) #str(f1)--->f1.__str__() # # x=str(f1) # print(x) # # y=f1.__str__() # print(y) 这三个结果是一样的,这个很重要,可以定义输出 在解释器中打印的时候触发的是__repr__ class Foo: def __init__(self,name,age): self.name=name self.age=age # def __str__(self): # return '这是str' def __repr__(self): return '名字是%s 年龄是%s' %(self.name,self.age) f1=Foo('egon',19) #repr(f1)---->f1.__repr__() print(f1) #str(f1)---》f1.__str__()------>f1.__repr__() 总结: ''' str函数或者print函数--->obj.__str__() repr或者交互式解释器--->obj.__repr__() 如果__str__没有被定义,那么就会使用__repr__来代替输出 注意:这俩方法的返回值必须是字符串,否则抛出异常 '''
类的内置属性__format__:
format_dic={ 'ymd':'{0.year}{0.mon}{0.day}', 'm-d-y':'{0.mon}-{0.day}-{0.year}', 'y:m:d':'{0.year}:{0.mon}:{0.day}' } class Date: def __init__(self,year,mon,day): self.year=year self.mon=mon self.day=day def __format__(self, format_spec): print('我执行啦') print('--->',format_spec) if not format_spec or format_spec not in format_dic: format_spec='ymd' fm=format_dic[format_spec] return fm.format(self)#必须有返回值 d1=Date(2016,12,26) # format(d1) #d1.__format__() #内置方法可以直接用函数调用 # print(format(d1)) print(format(d1,'ymd')) print(format(d1,'y:m:d')) print(format(d1,'m-d-y')) print(format(d1,'m-d:y')) print('===========>',format(d1,'asd'))
类的内置属性__slots__:
应用场景:属性较少实例较多的情况下,可用该方法(慎用) 这样定义实例化的实例就没有属性字典了, class Foo: __slots__=['name','age'] #{'name':None,'age':None}#只能定义slots提供的属性 # __slots__='name' #{'name':None,'age':None}#实例只能创建仅限一个属性 f1=Foo() # f1.name='egon' # print(f1.name) # f1.age=18 #--->setattr----->f1.__dict__['age']=18 # print(f1.__dict__) print(Foo.__slots__) print(f1.__slots__) f1.name='egon' f1.age=17 print(f1.name) print(f1.age)
类的内置属性__doc__
class Foo:
'我是描述信息'
pass
class Bar(Foo): #该属性不可继承,如果没有定义,默认是none
pass
类的内置属性__module__和__class__
查看实例属于哪个模块和类
类的内置属性析构函数__del__(♥♥♥♥♥♥♥♥♥♥♥♥)
垃圾回收机制,在实例被删除的时候会触发,删除实例属性的时候不会触发,当程序执行完毕的时候会自动触发该机制回收内存
类的内置属性__call__
class Foo: def __call__(self, *args, **kwargs): print('实例执行啦 obj()') f1=Foo() f1() #f1的类Foo 下的__call__ Foo() #Foo的类 xxx下的__call__
一个对象之所有可以加上()运行,就是因为他调用了__call__方法
类的内置方法__iter__和__next__
class Foo: def __init__(self,n): self.n=n def __iter__(self): return self def __next__(self): if self.n == 13: raise StopIteration('终止了')#跳出异常 self.n+=1 return self.n # l=list('hello') # for i in l: # print(i) f1=Foo(10) # print(f1.__next__()) # print(f1.__next__()) # print(f1.__next__()) # print(f1.__next__()) for i in f1: # obj=iter(f1)------------>f1.__iter__() print(i) #obj.__next_()#for循环会自动捕捉异常终止循环
描述符__get__、__set__、__del__:描述符的作用是用来代理另外一个类的属性的
class Foo:#数据描述符 def __get__(self, instance, owner): print('===>get方法') def __set__(self, instance, value): print('===>set方法',instance,value#这里的instance就是实例化的对象,value就是传的值 instance.__dict__['x']=value #b1.__dict__ def __delete__(self, instance): print('===>delete方法') class Bar: x=Foo() #在何地?#只要是在这个给类或者这个类实例化的的对象中对x进行操作,就会触发描述符的相关方法 def __init__(self,n): self.x=n #b1.x=10 #触发数据描述符,因为x被数据据描述符代理了 b1=Bar(10) Bar.x=6 #在定义类的属性的时候,优先级高于数据描述符,不会触发数据描述,会负载之前定义的描述符属性,通过属性字典可以查看
数据描述符定义:
一 描述符本身应该定义成新式类,被代理的类也应该是新式类
二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中
三 要严格遵循该优先级,优先级由高到底分别是
1.类属性
2.数据描述符
3.实例属性
4.非数据描述符
5.找不到的属性触发__getattr__()
1 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议
__get__():调用一个属性时,触发
__set__():为一个属性赋值时,触发
__delete__():采用del删除属性时,触发
2 描述符是干什么的:描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中)
3 描述符分两种
一 数据描述符:至少实现了__get__()和__set__()
二 非数据描述符:没有实现__set__()