内置函数补充及__getattribute__
isinstance(obj,cls)检查obj是否是类cls的实例,反映族谱关系(不仅父类可以,父类的父类也可以)
issubclass(subcls,cls)检查subcls是否是cls的子类
__getattribute__属性存不存在都会触发它 ‘大哥’ 里面抛出Attribute Error时交给小弟处理
__getattr__属性不存在触发 ‘小弟
item系列
item是字典方式触发的
__setitem__
__getitem__
__delitem__
1 class Foo: 2 def __getitem__(self, item): 3 print('getitem',item) 4 return self.__dict__[item] 5 6 def __setitem__(self, key, value): 7 print('setitem') 8 self.__dict__[key]=value 9 10 def __delitem__(self, key): 11 print('delitem') 12 self.__dict__.pop(key) 13 14 f1=Foo() 15 print(f1.__dict__) 16 # f1.name='egon' #---->点触发attr系列方法 17 f1['name']='egon' #--->中括号字典形式触发item系列方法 18 f1['age']=18 19 20 print('===>',f1.__dict__) 21 22 # del f1.name 23 # print(f1.__dict__) 24 25 # print(f1.age) 26 del f1['name'] 27 print(f1.__dict__) 28 29 print(f1['age'])
输出
{}
setitem
setitem
===> {'name': 'egon', 'age': 18}
delitem
{'age': 18}
getitem age
18
__str__和__repr__
1 class Foo: 2 def __init__(self,name,age): 3 self.name=name 4 self.age=age 5 def __repr__(self): 6 return 'this is repr' 7 # def __str__(self): 8 # return 'this is str' 9 f1=Foo('cy',23) 10 print(f1) #str(f1)-->f1.__str__()
输出
this is repr
st函数或者print函数--->obj.__str__()
repr函数或者交互式解释器--->obj.__repr__()
如果__str__没被定义,那就使用__repr__来代替输出
str和repr返回的必须是字符串,否则抛出异常
自定制format
1 format_dic={ 2 'ymd':'{0.year}{0.mon}{0.day}', 3 'm-d-y':'{0.mon}-{0.day}-{0.year}', 4 'y:m:d':'{0.year}:{0.mon}:{0.day}' 5 } 6 class Date: 7 def __init__(self,year,mon,day): 8 self.year=year 9 self.mon=mon 10 self.day=day 11 def __format__(self, format_spec): 12 print('执行__format__方法') 13 print('--->',format_spec) 14 if not format_spec or format_spec not in format_dic: 15 format_spec='ymd' 16 fm=format_dic[format_spec] 17 return fm.format(self) 18 d1=Date(2016,12,26) 19 # format(d1) #d1.__format__() 20 print('没设置格式,采用默认格式==>',format(d1)) 21 print(format(d1,'ymd')) 22 print(format(d1,'y:m:d')) 23 print(format(d1,'m-d-y')) 24 print('已设定格式但格式不存在,采用默认格式==>',format(d1,'m-d:y'))
输出
执行__format__方法
--->
没设置格式,采用默认格式==> 20161226
执行__format__方法
---> ymd
20161226
执行__format__方法
---> y:m:d
2016:12:26
执行__format__方法
---> m-d-y
12-26-2016
执行__format__方法
---> m-d:y
已设定格式但格式不存在,采用默认格式==> 20161226
__slots__
(慎用)是一个类变量,变量值可以是字符串、列表、元组或者可迭代对象(意味着所有实例只有一个数据属性)
为何使用__slots__?优势在于省内存(字典会占用大量内存,如果有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__,设置了__slots__之后,__dict__就没了)
使用点来访问属性本质就是在访问类或对象的__dict__属性字典(类的字典是共享的,而每个实例是独立的)
特点:不允许设置其他数据属性。
1 class Foo: 2 __slots__=['name','age'] #{'name':None,'age':None} 3 # __slots__='name' #{'name':None,'age':None} 4 5 f1=Foo() 6 # f1.name='egon' 7 # print(f1.name) 8 9 # f1.age=18 #--->setattr----->f1.__dict__['age']=18 10 11 # print(f1.__dict__) 12 print(Foo.__slots__) 13 print(f1.__slots__) 14 f1.name='egon' 15 f1.age=17 16 print(f1.name) 17 print(f1.age) 18 # f1.gender='male' 19 20 21 f2=Foo() 22 print(f2.__slots__) 23 f2.name='alex' 24 f2.age=18 25 print(f2.name) 26 print(f2.age)
输出
['name', 'age']
['name', 'age']
egon
17
['name', 'age']
alex
18
__doc__
定义于开头用来说明文档信息的一个字符串,且无法被继承。
写不写都有,不写默认是None。
__module__和__class__
查看实例来自哪个模块 对象.__module__
查看实例是什么类 对象.__class__
__del__ 析构方法
此方法一般无需定义,因为python是门高级语言,使用时无需关心内存的分配和释放,此工作交由python解释器执行,所以析构函数的调用是由解释器在进行垃圾回收时自动触发执行的,文件执行完毕之后触发该函数执行。
1 class Foo: 2 def __init__(self,name): 3 self.name=name 4 def __del__(self): 5 print('我执行啦') 6 7 f1=Foo('alex') 8 9 # del f1 #删除实例会触发__del__ 10 del f1.name #删除实例的属性不会触发__del__ 11 print('--------------------->') 12 13 #程序运行完毕会自动回收内存,触发__del__
输出
--------------------->
我执行啦
__call__
对象后面加括号,触发执行。
__next__和__iter__实现迭代器协议
1 class Foo: 2 def __init__(self,n): 3 self.n=n 4 def __iter__(self): 5 return self 6 7 def __next__(self): 8 if self.n == 13: 9 raise StopIteration('终止了') 10 self.n+=1 11 return self.n 12 13 f1=Foo(10) 14 15 for i in f1: # obj=iter(f1)------------>f1.__iter__() 16 print(i) #obj.__next__()
输出
11
12
13
迭代器协议实现斐波那契数列
1 class Fib: 2 def __init__(self): 3 self._a=1 4 self._b=1 5 6 def __iter__(self): 7 return self 8 def __next__(self): 9 if self._a > 100: 10 raise StopIteration('终止了') 11 self._a,self._b=self._b,self._a + self._b 12 return self._a 13 14 f1=Fib() 15 print(next(f1)) 16 print(next(f1)) 17 print(next(f1)) 18 print(next(f1)) 19 print(next(f1)) 20 print('==================================') 21 for i in f1: 22 print(i)
输出
1
2
3
5
8
==================================
13
21
34
55
89
144
描述符理论
(开发大型框架时用到)
本质是一个新式类,至少实现了__get__()/__set__()/__delete__()中的一个,这也被成为描述符协议。
__get__():调用一个属性时触发
__set__():为一个属性赋值时触发
__delete__():采用del删除属性时触发
描述符有什么用?描述符的作用是用来代理另外一个类的属性的
描述符分为两种:
数据描述符:至少实现了__get__()和__set__()
非数据描述符:没实现__set__()
注意事项:
1.描述符本身应该定义成新式类,被代理的类也应该是新式类;
2.必须把描述符定义成类属性,而不能定义到构造函数中;
3.要严格遵循该优先级,从高到低:
类属性---数据描述符---实例属性---非数据描述符---找不到的属性触发__getattr__()
例:
1 class Foo: 2 def __get__(self, instance, owner): 3 print('===>get方法') 4 def __set__(self, instance, value): 5 print('===>set方法',instance,value) 6 instance.__dict__['x']=value #对b1.__dict__进行修改 7 def __delete__(self, instance): 8 print('===>delete方法') 9 10 class Bar: 11 x=Foo() #描述符定义位置 在何地? x用描述符来描述 12 def __init__(self,n): 13 self.x=n #b1.x=10 触发Foo的set方法 14 #触发在何时? 15 b1=Bar(10) #在执行赋值操作 16 print(b1.__dict__) 17 b1.x=1 #在执行赋值操作 18 print(b1.__dict__) 19 20 b1.y=2 #没有触发set,因为变量y并没用描述符描述 21 print(b1.__dict__)
输出
===>set方法 <__main__.Bar object at 0x000001CDBB0197B8> 10
{'x': 10}
===>set方法 <__main__.Bar object at 0x000001CDBB0197B8> 1
{'x': 1}
{'x': 1, 'y': 2}
优先级的体现
1 class Foo: 2 def __get__(self, instance, owner): 3 print('===>get方法') 4 def __set__(self, instance, value): 5 print('===>set方法',instance,value) 6 instance.__dict__['x']=value #b1.__dict__ 7 def __delete__(self, instance): 8 print('===>delete方法') 9 10 class Bar: 11 x=Foo() 12 Bar.x=1 #覆盖类属性,改变了Bar的__dict__ 13 print(Bar.__dict__) 14 print(Bar.x)
输出
{'__module__': '__main__', 'x': 1, '__dict__': <attribute '__dict__' of 'Bar' objects>, '__weakref__': <attribute '__weakref__' of 'Bar' objects>, '__doc__': None}
1
反序列化的时候要保证类还在内存中。