内置函数补充及__getattribute__
isinstance(obj,cls)检查obj是否是类cls的实例,反映族谱关系(不仅父类可以,父类的父类也可以)
issubclass(subcls,cls)检查subcls是否是cls的子类
__getattribute__属性存不存在都会触发它 ‘大哥’ 里面抛出Attribute Error时交给小弟处理
__getattr__属性不存在触发 ‘小弟
item系列
item是字典方式触发的
__setitem__
__getitem__
__delitem__
代码语言:javascript复制 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__
代码语言:javascript复制 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
代码语言:javascript复制 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__属性字典(类的字典是共享的,而每个实例是独立的)
特点:不允许设置其他数据属性。
代码语言:javascript复制 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解释器执行,所以析构函数的调用是由解释器在进行垃圾回收时自动触发执行的,文件执行完毕之后触发该函数执行。
代码语言:javascript复制 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__实现迭代器协议
代码语言:javascript复制 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
迭代器协议实现斐波那契数列
代码语言:javascript复制 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__()
例:
代码语言:javascript复制 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}
优先级的体现
代码语言:javascript复制 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
反序列化的时候要保证类还在内存中。