Python面向对象编程Day 27部分

2020-01-19 11:52:45 浏览数 (1)

内置函数补充及__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

反序列化的时候要保证类还在内存中。

0 人点赞