一、什么是反射

  反射的概念是Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于用于反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。

二、四个可以实现自省的函数(下列方法适用于类和对象)

  1、hasattr(object,name)

    判断object中有没有一个name字符串对象的方法或属性

  2、getattr(object,name,defaullt=None)

    获取属性

  3、setattr(s,y,v)

    设置属性

  4、delattr(x,y)

    删除属性

 1 class BlackMedium:
 2     feature='Ugly'
 3     def __init__(self,name,addr):
 4         self.name=name
 5         self.addr=addr
 6
 7     def sell_house(self):
 8         print('%s 黑中介卖房子啦,傻逼才买呢,但是谁能证明自己不傻逼' %self.name)
 9     def rent_house(self):
10         print('%s 黑中介租房子啦,傻逼才租呢' %self.name)
11
12 b1=BlackMedium('万成置地','回龙观天露园')
13
14 #检测是否含有某属性
15 print(hasattr(b1,'name'))
16 print(hasattr(b1,'sell_house'))
17
18 #获取属性
19 n=getattr(b1,'name')
20 print(n)
21 func=getattr(b1,'rent_house')
22 func()
23
24 # getattr(b1,'aaaaaaaa') #报错
25 print(getattr(b1,'aaaaaaaa','不存在啊'))
26
27 #设置属性
28 setattr(b1,'sb',True)
29 setattr(b1,'show_name',lambda self:self.name+'sb')
30 print(b1.__dict__)
31 print(b1.show_name(b1))
32
33 #删除属性
34 delattr(b1,'addr')
35 delattr(b1,'show_name')
36 #delattr(b1,'show_name111')#不存在,则报错
37
38 print(b1.__dict__)

1 True
2 True
3 万成置地
4 万成置地 黑中介租房子啦,傻逼才租呢
5 不存在啊
6 {'name': '万成置地', 'addr': '回龙观天露园', 'sb': True, 'show_name': <function <lambda> at 0x005DF0C0>}
7 万成置地sb
8 {'name': '万成置地', 'sb': True}

结果

  总结:

    hasattr(obj,'属性') #obj.属性 是否存在 存在返回True
    getattr(obj,'属性') #获取obj.属性 不存在则报错
    getattr(obj,'属性','默认值') #获取obj.属性 不存在不会报错,返回那个默认值
    setattr(obj,'属性','属性的值') #obj.属性=属性的值
    delattr(obj,'属性') #del obj.属性

三、为什么要用反射:

  反射的好处及时:可以事先定义好街口,街口只有在被完成后才会真正执行,这事先额即插即用,这其实是一种后期绑定,即你可以事先把主要的逻辑谢写好(之定义接口),然后后期再去实现接口功能。

  示例:

1 class FtpClient: # 程序员A
2     'ftp客户端,但是还么有实现具体的功能'
3     def __init__(self,addr):
4         print('正在连接服务器[%s]' %addr)
5         self.addr=addr

 1 from module import FtpClient
 2 f1=FtpClient('192.168.1.1') #程序员B
 3 if hasattr(f1,'get'):
 4     func_get=getattr(f1,'get')
 5     func_get()
 6 else:
 7     print('---->不存在此方法')
 8     print('处理其他的逻辑')
 9
10 不影响alex的代码编写

四、动态导入模块  

  1、创建一个:m1文件夹,再它下面创建一个t.py文件

1 print('---------------->')
2 def test1():
3     print('test1')
4
5 def _test2():
6     print('test2')

  2、再新建一个a.py的文件

 1 module_t=__import__('m1.t') # 这种方式,导入的都是m1文件夹。
 2 print(module_t)
 3 module_t.t.test1() # 所以调用模块的方法,必须写全那个模块
 4 # from m1.t import * # 有私有模块,这样是不能调用的,必须写出模块的名字
 5 # from m1.t import test,_test2
 6
 7 import importlib
 8 m=importlib.import_module('m1.t') # 这种直接就是调用m1下的t.py模块
 9 print(m)
10 m.test1()
11 m._test2()

  结果:

1 ---------------->
2 <module 'm1' (namespace)>
3 test1
4 <module 'm1.t' from 'D:\\python\\day26\\m1\\t.py'>
5 test1
6 test2

五、三个参数,给对象添加属性  

  __setattr__ :添加/修改属性会触发它的执行

  __delattr__ :删除属性的时候回触发

  __getattr__ :只有在使用点调用属性且属性不存在的时候才会触发

  作用:系统内置函数属性(如果不自己定义,就用系统默认定义的)

综合应用示例:

 1 class Foo:
 2     x=1
 3     def __init__(self,y):
 4         self.y=y
 5
 6     def __getattr__(self, item):
 7         print('----> from getattr:你找的属性不存在')
 8
 9
10     def __setattr__(self, key, value):
11         print('----> from setattr')
12         # self.key=value #这就无限递归了,你好好想想
13         # self.__dict__[key]=value #应该使用它
14
15     def __delattr__(self, item):
16         print('----> from delattr')
17         # del self.item #无限递归了
18         self.__dict__.pop(item)
19
20 #__setattr__添加/修改属性会触发它的执行
21 f1=Foo(10)
22 print(f1.__dict__) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值
23 f1.z=3
24 print(f1.__dict__)
25
26 #__delattr__删除属性的时候会触发
27 f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作
28 del f1.a
29 print(f1.__dict__)
30
31 #__getattr__只有在使用点调用属性且属性不存在的时候才会触发
32 f1.xxxxxx

分开使用:

  示例:__getattr__(常用,重点)

 1 class Foo:
 2     x=1
 3     def __init__(self,y):
 4         self.y=y
 5
 6     def __getattr__(self, item):
 7         print('执行__getattr__')
 8
 9 f1=Foo(10)
10 print(f1.y)
11
12 #没有的时候就会触发: __getattr__
13 print(getattr(f1,'y'))  #len(str)---->str.__len__()
14 f1.ssssssssssssssssssssssssssssss

结果:

1 10
2 10
3 执行__getattr__

  示例2:__delattr__(不常用)

 1 class Foo:
 2     x=1
 3     def __init__(self,y):
 4         self.y=y
 5
 6     def __delattr__(self, item):
 7         print('删除操作__delattr__')
 8
 9 f1=Foo(10)
10 del f1.y
11 del f1.x

  示例3: __setattr__(不常用)

 1 class Foo:
 2     x=1
 3     def __init__(self,y):
 4         self.y=y
 5
 6     def __setattr__(self,key,value):
 7         print('__setattr__执行')
 8         #self.key=value
 9         self.__dict__[key]=value
10
11 #增加键、值到字典中
12 f1=Foo(10)
13 print(f1.__dict__)
14
15 f1.z=2
16 print(f1.__dict__)

总结:

  obj点的方式去操作属性时触发的方法

  __getattr__:obj.属性 不存在时触发
  __setattr__:obj.属性=属性的值 时触发
  __delattr__:del obj.属性 时触发

六、二次加工标准类型(包装)

  包装:Python为大家提供了标准数据类型,以及丰富的内置方法,其实很多场景下我们都需要基于标砖数据类型来定制我们自己的数据类型,新增/改写方法,这就是用到了我们刚刚学的继承/派生知识(其他的标准类型均可以他通过下面的方式进行二次加工)

 1 class List(list): # 继承了list 父类
 2     def append(self, p_object):
 3         '我改写的方法'
 4         if not isinstance(p_object,str):
 5             print('只有字符串类型能被添加到列表中')
 6             return
 7         # self.append(p_object) #进入无限递归
 8         super().append(p_object)
 9     def show_mid(self):
10         '我新增的方法'
11         index=int(len(self)/2)
12         print(self[index])
13
14
15 l1=List('hello')
16
17 l1.append('abc')
18 print(l1,type(l1))
19
20 #数字无法添加成功
21 l1.append(1)
22 print('-->',l1)
23
24 #基于标准类型新增了功能
25 l1.show_mid()

授权:授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。

实现授权的关键点就是覆盖__getattr__方法

1、通过触发__getattr__方法,找到read方法

示例:

 1 import time
 2 class FileHandle:
 3     def __init__(self,filename,mode='r',encoding='utf-8'):
 4         self.file=open(filename,mode,encoding=encoding) # 通过原方法获取文件句柄
 5         self.mode=mode
 6         self.encoding=encoding
 7
 8     def __getattr__(self, item):
 9           print(item,type(item))
10           self.file.read         #self.file里面有read方法
11           return getattr(self.file,item)  #能过字符串来找到,并通过return返回,就找到了read方法,
12
13 f1=FileHandle('a.txt','r')
14 print(f1.file)
15 print(f1.__dict__)   #类的字典里,没有read方法,就触发了__getattr__方法
16 print(f1.read)       #找到了read方法
17
18 sys_f=open('b.txt','w+')
19 print('---->',getattr(sys_f,'read'))   #找到了read方法

结果:

1 <_io.TextIOWrapper name='a.txt' mode='r' encoding='utf-8'>
2
3 read <class 'str'>
4
5 <built-in method read of _io.TextIOWrapper object at 0x01638EB0>
6
7 {'encoding': 'utf-8', 'file': <_io.TextIOWrapper name='a.txt' mode='r' encoding='utf-8'>, 'mode': 'r'}
8
9 ----> <built-in method read of _io.TextIOWrapper object at 0x01638F30>

2、往文件里面写入内容

示例:

 1 import time
 2 class FileHandle:
 3     def __init__(self,filename,mode='r',encoding='utf-8'):
 4         # self.filename=filename
 5         self.file=open(filename,mode,encoding=encoding)
 6         self.mode=mode
 7         self.encoding=encoding
 8     def write(self,line):
 9         print('------------>',line)
10         t=time.strftime('%Y-%m-%d %X')
11         self.file.write('%s %s' %(t,line))
12
13     def __getattr__(self, item):
14         # print(item,type(item))
15         # self.file.read
16         return getattr(self.file,item)
17
18 f1=FileHandle('a.txt','w+')
19 f1.write('1111111111111111\n')
20 f1.write('cpu负载过高\n')
21 f1.write('内存剩余不足\n')
22 f1.write('硬盘剩余不足\n')

执行结果:

会创建一个a.txt的文件,并往里面写入内容:

1 2016-12-23 18:34:16 1111111111111111
2 2016-12-23 18:34:16 cpu负载过高
3 2016-12-23 18:34:16 内存剩余不足
4 2016-12-23 18:34:16 硬盘剩余不足

 七、isinstance(obj,cls) 和 issubclass(sub,super)

  1、isinstance(obj,cls) 检查是否obj 是否是类cls的对象

1 class Foo(object):
2     pass
3
4 obj = Foo()
5
6 print(isinstance(obj,Foo)) # True

  2、issubclass(sub,super) 检查sub类是否是supper类的派生类(继承)

1 class Foo(object):
2     pass
3
4 class Bar(Foo):
5     pass
6
7 print(issubclass(Bar,Foo)) # True

八、__getattribute__

  示例1:不存在的属性访问,就会触发__getattr__方法

 1 class Foo:
 2     def __init__(self,x):
 3         self.x=x
 4
 5     def __getattr__(self, item):
 6         print('执行的是我')
 7         #return self.__idct__[item]
 8
 9 f1=Foo(10)
10 print(f1.x)
11 f1.xxxxxx  #不存在的属性访问,触发__getattr__

  执行结果:

1 10
2 执行的是我

  示例2:不管是否存在,都会执行__getattribute__方法

 1 class Foo:
 2     def __init__(self,x):
 3         self.x=x
 4
 5     def __getattribute__(self, item):
 6         print('不管是否存在,我都会执行')
 7
 8 f1=Foo(10)
 9 f1.x
10 f1.xxxxxxx
11
12
13 ----------------------------------
14 不管是否存在,我都会执行
15 不管是否存在,我都会执行

  示例3:

 1 class Foo:
 2     def __init__(self,x):
 3         self.x=x
 4
 5     def __getattr__(self, item):   #相当于监听大哥的异常,大哥抛出导常,他就会接收。-----item就是调用的属性名,x    xxxxxxx
 6         print('执行的是我')
 7         # return self.__dict__[item]
 8
 9     def __getattribute__(self, item):
10         print('不管是否存在,我都会执行')
11         raise AttributeError('抛出异常了')
12
13 f1=Foo(10)
14 f1.x         #结果是:10 ,调用会触发系统的
15 f1.xxxxxxx   #如果不存在会触发自己定义的
16
17 ---------------------------------------------
18 不管是否存在,我都会执行
19 执行的是我
20 不管是否存在,我都会执行
21 执行的是我

 九、__setitem__, __getitem__, __deelitem__ (操作字典就用item的方式)

  obj['属性'] 的方式去操作属性时触发的方法

  __getitem__:obj['属性'] 时触发

  __setitem__ :obj['属性']  = 属性值 时触发

  __delitem__  :del  obj['属性'] 时触发

  

  示例:

 1 class Foo:
 2
 3     def __getitem__(self, item):
 4         print('getitem', item)
 5         return self.__dict__[item]
 6
 7     def __setitem__(self, key, value):
 8         print('setitem')
 9         self.__dict__[key] = value
10
11     def __delitem__(self, key):
12         print('delitem')
13         self.__dict__.pop(key)
14
15
16 f1 = Foo()
17 print(f1.__dict__)
18 f1['name'] = 'agon' #setitem
19 f1['age'] = 18
20 print('====>', f1.__dict__)
21
22 del f1['name'] # delitem
23 print(f1.__dict__)
24
25 print(f1['age']) # 调用getitem
26
27
28
29 ---------------------------------------------
30 {}
31 setitem
32 setitem
33 ====> {'name': 'agon', 'age': 18}
34 delitem
35 {'age': 18}
36 getitem age
37 18

  示例2:

 1 class Foo:
 2     def __init__(self,name):
 3         self.name=name
 4
 5     def __getitem__(self, item):
 6         print(self.__dict__[item])
 7
 8     def __setitem__(self, key, value):
 9         self.__dict__[key]=value
10     def __delitem__(self, key):
11         print('del obj[key]时,我执行')
12         self.__dict__.pop(key)
13     def __delattr__(self, item):
14         print('del obj.key时,我执行')
15         self.__dict__.pop(item)
16
17 f1=Foo('sb') # 实例化
18 f1['age']=18 # 添加属性age
19 f1['age1']=19
20 print(f1.__dict__)
21
22 del f1.age1 # 不会触发delitem,触发delattr
23 print(f1.__dict__)
24
25 del f1['age'] # 删除属性age
26 f1['name']='alex'
27 print(f1.__dict__)
28
29
30
31
32 ----------------------------
33
34 {'name': 'sb', 'age': 18, 'age1': 19}
35 del obj.key时,我执行
36 {'name': 'sb', 'age': 18}
37 del obj[key]时,我执行
38 {'name': 'alex'}

十、__str__   __repr__   __format__

  1、改变对象的字符串显示__str__   __repr__(只能是字符串的值,不能是非字符串的值)

  示例1:

1 l = list('hello')
2 print(1)
3
4 file=open('test.txt','w')
5 print(file)
6
7 -----------------------------
8 1
9 <_io.TextIOWrapper name='test.txt' mode='w' encoding='cp936'>

  示例2:__str__ 方法

 1 #自制str方法
 2 class Foo:
 3     def __init__(self,name,age):
 4         self.name=name
 5         self.age=age
 6
 7     def __str__(self):
 8         return '名字是%s 年龄是%s' %(self.name,self.age)
 9
10 f1=Foo('age',18)
11 print(f1)  #背后实际上是 触发:str(f1)---->f1.__str__(),现在是覆盖了__str__()方法
12
13 x=str(f1)
14 print(x)
15
16 y=f1.__str__()
17 print(y)
18
19
20 ----------------------------
21
22 名字是age 年龄是18
23 名字是age 年龄是18
24 名字是age 年龄是18

  示例3: __repr__方法

 1 #触发__repr__方法,用在解释器里输出
 2 class Foo:
 3     def __init__(self,name,age):
 4         self.name=name
 5         self.age=age
 6
 7     def __repr__(self):
 8         return '名字是%s 年龄是%s' %(self.name,self.age)
 9
10 f1=Foo('agon',19)
11 print(f1)
12
13 ---------
14 名字是agon 年龄是19

  示例4:__str__   __repr__ 共存

 1 # 当str与repr共存时
 2 class Foo:
 3     def __init__(self,name,age):
 4         self.name=name
 5         self.age=age
 6
 7     def __str__(self):
 8         return '名字是%s + 年龄是%s' % (self.name,self.age)
 9         #return 'a'
10     def __repr__(self):
11         return '名字是%s 年龄是%s' %(self.name,self.age)
12
13 f1=Foo('egon',19)
14             #repr(f1)--->f1.__repr__()
15 print(f1)  #str(f1)--->f1.__str__()---->f1.__repr__()

 总结:

    str函数或者print函数 调用的是obj.__str__()

    repr或者交互式解释器 调用的是obj.__repr__()

    如果__str__没有被定义,那么就会使用__repr__来替代输出

    注意:这两方法的返回值必须是字符串,否则抛出异常

  2、自定制格式化字符串__format__  

  

  format的用法:

  示例1:  博客: http://www.cnblogs.com/JerryZao/p/8604102.html

1 x = '{0}{0}{0}'.format('dog')
2 print(x)   # dogdogdog

  不用__format__的方式实现

  示例2:

 1 class Date:
 2     def __init__(self,year,mon,day):
 3         self.year=year
 4         self.mon=mon
 5         self.day=day
 6
 7 d1=Date(2016,12,26)
 8 print(d1)
 9
10 x = '{0.year}{0.mon}{0.day}'.format(d1) # 0 代表di对象,0.year就是调用属性
11 y = '{0.year}:{0.mon}:{0.day}'.format(d1)
12 z = '{0.year}-{0.mon}-{0.day}'.format(d1)
13 print(x)
14 print(y)
15 print(z)
16
17 ---------------------------------------------------
18
19 <__main__.Date object at 0x0041F810>
20 20161226
21 2016:12:26
22 2016-12-26

  用__format__的方式实现

  示例3:

 1 format_dic={ #定义一个格式字典
 2     'ymd':'{0.year}:{0.month}:{0.day}',
 3     'm-d-y':'{0.month}-{0.day}-{0.year}',
 4     'y:m:d':'{0.year}:{0.month}:{0.day}',
 5 }
 6
 7 class Date:
 8     def __init__(self,year,month,day):
 9         self.year=year
10         self.month=month
11         self.day=day
12
13     def __format__(self, format_spec):
14         print('我执行啦')
15         print('----->',format_spec)
16         if not format_spec or format_spec not in format_dic:
17             format_spec='ymd'
18         fmt=format_dic[format_spec]
19         return fmt.format(self) # 相当于 '{0.year}:{0.month}:{0.day}'.format(d1)
20
21 d1=Date(2016,12,29)
22 # print(format(d1))  #d1.__format__()
23 # print(format(d1))
24
25 print(format(d1,'ymd'))
26 print(format(d1,'y:m:d'))
27 print(format(d1,'m-d-y'))
28 print(format(d1,'m-d:y'))
29 print('===========>',format(d1,'sdsdddsfdsfdsfdsfdsfsdfdsfsdfds'))
30
31
32 ----------------------
33 我执行啦
34 -----> ymd
35 2016:12:29
36 我执行啦
37 -----> y:m:d
38 2016:12:29
39 我执行啦
40 -----> m-d-y
41 12-29-2016
42 我执行啦
43 -----> m-d:y
44 2016:12:29
45 我执行啦
46 -----> sdsdddsfdsfdsfdsfdsfsdfdsfsdfds
47 ===========> 2016:12:29

 十一:__slots__ (慎用)

  1、__slots__ 是一个变量,变量值可以是列表,元组,或者可迭代对象,可以是一个字符串(意味着所有实例只有一个数据属性)。

  2、引子:使用点来访问属性本事就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例的属性时独立的)。

  3、为何使用__slots__:字典会占用大量内存,如果你有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__当你定义__slots__后,__solts__就会为实例使用一种更加紧凑的内部标识。实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个字典,这跟元组或列表类似。在__slots__中列出的属性名在内部被映射到这个数组的指定小标上。使用__slots__一个不好的地方就是我们不能再给实例添加新的属性了,只能使用__slots__中定义的那些属性名。

  4、注意事项:__slots__的很多特性都依赖于普通的基于字典的实现。另外,定义了__slots__后的类不再支持一些普通类特性了,比如多继承。大多数情况下,,你应该只在那些经常被使用到的用作数据结构的类上定义__slots__比如在程序中需要创建某个类的几百万个实例对象。关于__slots__的一个常见误区是它可以作为一个封装工具来防止用户给实例增加新的属性。尽管使用__slots__可以达到这样的目的,但是这个并不是它的初衷。更多的是用来作为一个内存优化工具。

  

__slots__的作用:节省内存空间

  1:一个key的情况

  示例1:

 1 #__slots__  (作用:就是节省内存)
 2 #一个key的值
 3
 4 class Foo:
 5     __slots__='name'  #定义在类中的类变量,由这个类产生的实例,不在具有__dict__的属性字典,限制了创建属性
 6
 7 f1=Foo()
 8 f1.name='agon'
 9 print(f1.name)         #只能有一个name属性
10 print(Foo.__slots__)
11 print(f1.__slots__)
12
13
14 ----------------------------
15 agon
16 name
17 name

  2、两个key的情况:

  示例2:

 1 #两个key的情况
 2 class Foo:
 3     __slots__=['name','age']
 4
 5 f1=Foo()
 6
 7 print(Foo.__slots__)
 8 print(f1.__slots__)
 9
10 f1.name='egon'
11 f1.age=17
12
13 print(f1.name)
14 print(f1.age)
15 # f1.gender='male'   #会报错,加不上,#AttributeError: 'Foo' object has no attribute 'gender'
16
17 #只能定义__slots__提供的属性(这里就定义了两个属性)大家都用一个属性字典,优势就是节省内存
18 f2=Foo()
19 print(f2.__slots__)
20 f2.name='alex'
21 f2.age=18
22 print(f2.name)
23 print(f2.age)
24
25
26 ----------------------------------------------------
27
28 ['name', 'age']
29 ['name', 'age']
30 egon
31 17
32 ['name', 'age']
33 alex
34 18

十二、__doc__

  1、类的描述信息

  示例:

1 class Foo:
2     '我是描述信息'
3     pass
4
5 print(Foo.__doc__)

  2、该属性无法继承(每个类默认都会提供)

#__doc__ 该属性无法继承class Foo:passclass Bar(Foo):passprint(Foo.__dict__)  #只要加上了__doc__,该属性就无法继承给子类
print(Bar.__dict__)  #原理就是在底层字典里面,会加一个'__doc__': None,

十三、__module__和__class__

  __module__ 表示当前操作的对象在哪个模块

  __class__      表示当前操作的对象的类是什么

  1、创建lib/aa.py

1 #!/usr/bin/env python
2 # -*- coding:utf-8 -*-
3
4 class C:
5
6     def __init__(self):
7         self.name = ‘SB'
8

  2、出书模块 和 输出类

1 from lib.aa import C
2
3 obj = C()
4 print obj.__module__     #输出 lib.aa,即:输出模块,obj来自哪个模块
5 print obj.__class__      #输出 lib.aa.C,即:输出类,obj来自哪个类

十四、__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
14
15 1 ---------------->
16 2 我执行啦

View Code

十五、__call__

  对象后面加上括号,触发执行。

  注:构造方法的执行是由对象触发的,即:对象=类名()   而对于__call__方法的执行是由对象后加括号触发的,即:类()() 或者对象()

 1 class Foo:
 2
 3     def __init__(self):
 4         pass
 5
 6     def __call__(self, *args, **kwargs):
 7         print('__call__')
 8         print(self)
 9         print(args)
10         print(kwargs)
11
12
13
14 obj = Foo()  # 执行 __init__
15 print(obj)
16 obj([2,3,4],s=1)  # 执行 __call__
17
18
19 --------------------------------------------
20 <__main__.Foo object at 0x0024F870>
21 __call__
22 <__main__.Foo object at 0x0024F870>
23 ([2, 3, 4],)
24 {'s': 1}

十六、__next__ 和__iter__ 实现迭代器协议

  一、什么是迭代器协议 

  1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前退)

  2.可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义一个__iter__()方法)

  3.协议是一种约定,可迭代对象实现了迭代器协议,python的内部工具(如for循环,sum,min,max函数等)使用迭代器协议访问对象。

  二、python中强大的for循环 

  for循环的本质:循环所有对象,全都是使用迭代器协议。

  (字符串,列表,元组,字典,集合,文件对象)这些都不是可迭代对象,只不过在for循环式,调用了他们内部的__iter__方法,把他们变成了可迭代对象

  然后for循环调用可迭代对象的__next__方法去取值,而且for循环会捕捉StopIteration异常,以终止迭代。

  

  示例1:

  

 1 class Foo:
 2     def __init__(self,n):
 3         self.n=n
 4
 5     def __iter__(self):  #把一个对象就成一个可迭代对象,必须有__iter__
 6         return self
 7
 8     def __next__(self):
 9         self.n+=1
10         return self.n
11
12 f1=Foo(10)
13 # for i in f1:  #for循环本质就是调用他:f1.__iter__() == iter(f1)
14 #     print(i)
15
16 print(f1.__next__())
17 print(next(f1))
18 print(next(f1))
19 print(next(f1))
20 print(next(f1))
21 print(next(f1))
22
23
24 for i in f1:  #for循环本质就是调用他:f1.__iter__() == iter(f1)
25     print(i)
26
27 --------------------------------------------------
28
29 11
30 12
31 13
32 14
33 15
34 16
35 17
36 18
37 19
38 20
39 21
40 22
41 23
42 24
43 25
44 26
45 会一直无限循环下去.....
46 下面部分省略.....

  示例2:

 1 class Foo:
 2     def __init__(self,n):
 3         self.n=n
 4
 5     def __iter__(self):  #把一个对象就成一个可迭代对象,必须有__iter__
 6         return self
 7
 8     def __next__(self):
 9         if self.n == 13:
10             raise StopIteration('终止了')
11         self.n+=1
12         return self.n
13
14
15 f1=Foo(10)
16
17 # print(f1.__next__())
18 # print(f1.__next__())
19 # print(f1.__next__())
20 # print(f1.__next__())
21
22 for i in f1:  #f1.__iter__() == iter(f1)
23     print(i)  #obj.__next__()
24
25 ------------------------------------------------------
26 11
27 12
28 13

  三、菲波那切数列

  用迭代器协议的方法实现:一次产生一个值

 1 #斐波那契数列
 2 class Fib:
 3     def __init__(self):
 4         self._a=1
 5         self._b=1
 6
 7     def __iter__(self):
 8         return self
 9     def __next__(self):
10         if self._a > 100:
11             raise StopIteration('终止了')  # >100 就抛出异常
12         self._a, self._b = self._b, self._a + self._b   #1+1=b; a,b=b,a(等于交换值)
13         return self._a
14
15 f1=Fib()
16 print(next(f1))
17 print(next(f1))
18 print(next(f1))
19 print(next(f1))
20 print(next(f1))
21 print('==================================')# 从上次next的位置继续
22 for i in f1:
23     print(i)
24
25
26 ----------------------------------
27 1
28 2
29 3
30 5
31 8
32 ==================================
33 13
34 21
35 34
36 55
37 89
38 144

十七、描述符(__get__ __set__ __delete__)(新式类中描述符在大型开发中常用,必须掌握)

  描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__()   __set__()  __delete__() 三个方法中的一个,这也被称为描述符协议。

 1 class 描述符:
 2     def __get__():
 3         pass
 4     def __set__():
 5         pass
 6     def __delete__():
 7         pass
 8
 9 class 类:
10     name=描述符()
11
12 obj=类()
13 obj.name        #get方法
14 obj.name='egon' #set方法
15 del obj.name    #delete  

  描述符的三种方法:

    __get__():  .调用一个属性时,触发
    __set__():   .为一个属性赋值时,触发
    __delete__():  采用del.删除属性时,触发

  1、定义一个描述符

  示例1:

1 class Foo:   #在python3中Foo是新式类,它实现了三种方法,这个类就被称作一个描述符
2     def __get__(self,instance,owner):
3         print('get方法')
4     def __set__(self, instance, value):
5         print('set方法')
6     def __delete__(self, instance):
7         print('delete方法')

  2、描述符是干什么的:描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中)

 1 class Foo:
 2     def __get__(self,instance,owner):
 3         print('===>get方法')
 4     def __set__(self, instance, value):
 5         print('===>set方法')
 6     def __delete__(self, instance):
 7         print('===>delete方法')
 8
 9 #包含这三个方法的新式类称为描述符,由这个类产生的实例进行属性的调用/赋值/删除,并不会触发这三个方法
10 f1=Foo()
11 f1.name='egon'
12 print(f1.name)
13 del f1.name
14 #疑问:何时,何地,会触发这三个方法的执行

  3、描述符应用之何时?何地?

  示例3:

 1 #描述符应用之何时?何地?
 2 #描述符Str
 3 class Foo:
 4     def __get__(self,instance,owner):
 5         print('===>get方法')
 6     def __set__(self, instance, value):
 7         print('===>set方法')
 8     def __delete__(self, instance):
 9         print('===>delete方法')
10
11 class Bar:
12     x=Foo() #在何地?
13
14 # print(Bar.__dict__)#在何时?
15
16 b1=Bar()
17 b1.x                 #调用就会触发上面的get方法
18 b1.x=1               #赋值
19 del b1.x
20
21 print(b1.x)            #触发了描述器里面的get方法,得到None
22 b1.x=1                 #触发了描述器里面的set方法,得到{}
23 print(b1.__dict__)     #写到b1的属性字典中
24 del b1.x               #打印===>delete方法
25
26 ---------------------------------------------------------
27 ===>get方法
28 ===>set方法
29 ===>delete方法
30 ===>get方法
31 None
32 ===>set方法
33 {}
34 ===>delete方法

  4、描述符分为两种

  ①、数据描述符:至少实现了__get__() 和 __set__()两种方法

  示例: 

1 class Foo:
2     def __set__(self, instance, value):
3         print('set')
4     def __get__(self, instance, owner):
5         print('get')

  ②、非数据描述符:没有实现__set__()方法

  示例:

1 class Foo:
2     def __get__(self, instance, owner):
3         print('get')

  5、注意事项:

  ① 描述符本身应该定义成新式类,被代理的类也应该是新式类

  ② 必须把描述符定义成另外一个雷触发的属性类,不能定义到构造函数中 init  call

 1 class Foo:
 2     def __get__(self, instance, owner):
 3         print('===>get方法')
 4         print('+++', self) # Foo的对象 x
 5         print('---', instance) # Bar的对象 b1
 6         print('===', owner) # Bar类
 7     def __set__(self, instance, value):
 8         print('===>set方法')
 9         print('---', instance)  # Bar的对象
10         print('===', value) # 设置的值
11     def __delete__(self, instance):
12         print('===>delete方法')
13         print(self) # Foo的对象
14         print(instance)
15
16 class Bar:
17     x=Foo() #定义一个描述符
18     def __init__(self,n):
19         self.x=n
20
21 b1=Bar(10)   #触发set方法
22 # print(b1)
23 # print(b1.__dict__)
24 print('-------------------------------------------')
25 b1.x
26 print('----------------------------------------------')
27 del b1.x
28
29
30
31 ------------------------------------------------------------------------------------
32
33 ===>set方法
34 --- <__main__.Bar object at 0x01E3AB90>
35 === 10
36 -------------------------------------------
37 ===>get方法
38 +++ <__main__.Foo object at 0x005ACF30>
39 --- <__main__.Bar object at 0x01E3AB90>
40 === <class '__main__.Bar'>
41 ----------------------------------------------
42 ===>delete方法
43 <__main__.Foo object at 0x005ACF30>
44 <__main__.Bar object at 0x01E3AB90>

  三、要严格遵循该优先级,优先级由高到底分别是:

  1、类属性

  2、数据描述符

  3、实例属性

  4、非数据描述符

  5、找不到的属性触发__getattr__()

  类属性>数据描述符

   示例:

 1 class Foo:
 2     def __get__(self,instance,owner):
 3         print('===>get方法')
 4     def __set__(self, instance, value):
 5         print('===>set方法')
 6     def __delete__(self, instance):
 7         print('===>delete方法')
 8
 9 class Bar:
10     x=Foo()   #调用foo()属性,会触发get方法
11     def __init__(self,x):
12         self.x = x
13
14 print(Bar.x)  # 1、类属性比描述符有更高的优先级,会触发get方法
15
16 Bar.x=1       #2、 自己定义了一个类属性,并赋值给x,跟描述符没有关系,所以他不会触发描述符的方法
17 print(Bar.__dict__)
18
19 print(Bar.x)
20
21 ------------------------------------------------------------------
22
23 ===>get方法
24 None
25 {'__module__': '__main__', 'x': 1, '__init__': <function Bar.__init__ at 0x0242E108>, '__dict__': <attribute '__dict__' of 'Bar' objects>, '__weakref__': <attribute '__weakref__' of 'Bar' objects>, '__doc__': None}
26 1

  数据描述符>实例属性

  示例:

 1 #有get,set就是数据描述符,数据描述符比实例属性有更高的优化级
 2
 3 class Foo:
 4     def __get__(self,instance,owner):
 5         print('===>get方法')
 6     def __set__(self, instance, value):
 7         print('===>set方法')
 8     def __delete__(self, instance):
 9         print('===>delete方法')
10
11 class Bar:
12     x = Foo()  # 调用foo()属性,会触发get方法
13     def __init__(self,x,y):
14         self.x = x
15         self.y = y
16
17
18 b1=Bar(1,2)   #在自己的属性字典里面找,找不到就去类里面找,会触发__get__方法
19 b1.x       #调用一个属性的时候触发get方法
20 b1.x=1     #为一个属性赋值的时候触发set方法
21 del b1.x   #采用del删除属性时触发delete方法
22
23
24
25 ===>set方法
26 ===>get方法
27 ===>set方法
28 ===>delete方法

  示例:

 1 class Foo:
 2     def __get__(self,instance,owner):
 3         print('===>get方法')
 4
 5     def __set__(self, instance, value):
 6         pass
 7
 8 class Bar:
 9     x = Foo()
10
11 b1=Bar()
12 b1.x=1        # 触发的是非数据描述符的set方法
13 print(b1.__dict__)
14
15
16 ------------------------------------------
17 {}   #数据描述符>实例属性

  类属性>数据描述符>实例属性

 1 #类属性>数据描述符>实例属性
 2
 3 class Foo:
 4     def __get__(self,instance,owner):
 5         print('===>get方法')
 6     def __set__(self, instance, value):
 7         print('===>set方法')
 8     def __delete__(self, instance):
 9         print('===>delete方法')
10
11 class Bar:
12     x = Foo()             #调用foo()属性,会触发get方法
13
14 b1=Bar()                  #实例化
15 Bar.x=11111111111111111   #不会触发get方法
16 b1.x                      #会触发get方法
17
18 del Bar.x                 #已经给删除,所以调用不了!报错:AttributeError: 'Bar' object has no attribute 'x'
19 b1.x

  非数据描述符

    示例1:

 1 #非数据描述符没有set方法
 2 class Foo:
 3     def __get__(self,instance,owner):
 4         print('===>get方法')
 5
 6     def __delete__(self, instance):
 7         print('===>delete方法')
 8
 9 class Bar:
10     x = Foo()
11
12 b1=Bar()
13 b1.x     #自己类中没有,就会去Foo类中找,所以就会触发__get__方法
===>get方法
 

    示例2:

 1 #实例属性>非数据描述符
 2 class Foo:
 3     def __get__(self,instance,owner):
 4         print('===>get方法')
 5
 6 class Bar:
 7     x = Foo()
 8
 9 b1=Bar()
10 b1.x=1
11 print(b1.__dict__)  #在自己的属性字典里面,{'x': 1}
12
13
14 ---------------------------------------------------------
15 {'x': 1}

  非数据描述符>找不到

  

 1 #非数据描述符>找不到
 2
 3 class Foo:
 4     def __get__(self,instance,owner):
 5         print('===>get方法')
 6
 7 class Bar:
 8     x = Foo()
 9     def __getattr__(self, item):
10         print('------------>')
11
12 b1=Bar()
13 b1.xxxxxxxxxxxxxxxxxxx    #调用没有的xxxxxxx,就会触发__getattr__方法
14
15
16 --------------------------------------------------
17 #非数据描述符>找不到
18
19 class Foo:
20     def __get__(self,instance,owner):
21         print('===>get方法')
22
23 class Bar:
24     x = Foo()
25     def __getattr__(self, item):
26         print('------------>')
27
28 b1=Bar()
29 b1.xxxxxxxxxxxxxxxxxxx    #调用没有的xxxxxxx,就会触发__getattr__方法
30
31 -------------------------------------------------
32 ------------>    #解发__getattr__方法

  四、描述符的应用

  示例1:

 1 class Typed:   #有__get__,__set__,__delete__ 就是:数据描述符
 2     def __get__(self, instance,owner):
 3         print('get方法')
 4         print('instance参数【%s】' %instance)
 5         print('owner参数【%s】' %owner)
 6
 7     def __set__(self, instance, value):
 8         print('set方法')
 9         print('instance参数【%s】' %instance)
10         print('value参数【%s】' %value)
11
12     def __delete__(self, instance):
13         print('delete方法')
14         print('instance参数【%s】'% instance)
15 class People:
16     name=Typed()    #设置代理(代理的就是name属性)
17     def __init__(self,name,age,salary):
18         self.name=name        #触发的是代理
19         self.age=age
20         self.salary=salary
21
22 p1=People('alex',13,13.3)
23 #'alex'             #触发set方法
24 p1.name             #触发get方法,没有返回值
25 p1.name='age'       #触发set方法
26 print(p1.__dict__)  #{'salary': 13.3, 'age': 13}
27
28
29 ---------------------------------------------------------------
30 set方法
31 instance参数【<__main__.People object at 0x0025F870>】
32 value参数【alex】
33 get方法
34 instance参数【<__main__.People object at 0x0025F870>】
35 owner参数【<class '__main__.People'>】
36 set方法
37 instance参数【<__main__.People object at 0x0025F870>】
38 value参数【age】
39 {'age': 13, 'salary': 13.3}

  示例2:给字典属性传值

 1 #给字典里面传入值
 2 class Typed:
 3     def __init__(self,key):
 4         self.key=key
 5     def __get__(self, instance, owner):
 6         print('get方法')
 7         print(self.key)
 8         return instance.__dict__[self.key]   #触发get方法,会返回字典的值
 9     def __set__(self, instance, value):
10         print('set方法')
11         print(self.key)
12         instance.__dict__[self.key]=value     #存在p1的属性字典里面
13     def __delete__(self, instance):
14         print('delete方法')
15         instance.__dict__.pop(self.key)
16 class People:
17     name=Typed('name')      #name属性被Typed给代理了,t1._set_() self._set__()
18     def __init__(self,name,age,salary):
19         self.name=name
20         self.age=age
21         self.salary=salary
22 p1=People('alex',13,13.3)
23 #打印实例字典
24 print(p1.__dict__)
25 # #创建属性,给name赋值,相当于修改了name字典的值
26 p1.name='egon'             #触发的是set方法
27 print(p1.__dict__)
28 # #删除name属性
29 # print(p1.__dict__)
30 del p1.name               #触发的是delete方法
31 print(p1.__dict__)
32
33
34 -------------------------------------------------------------------------
35
36 set方法
37 name
38 {'name': 'alex', 'age': 13, 'salary': 13.3}
39 set方法
40 name
41 {'name': 'egon', 'age': 13, 'salary': 13.3}
42 delete方法
43 {'age': 13, 'salary': 13.3}

  示例3:实现类型检测的两种方法:

  方法一:用return的方式:

 1 #判断他传入的值是不是字符串类型
 2 class Typed:
 3     def __init__(self,key):
 4         self.key=key
 5
 6     def __get__(self, instance, owner):
 7         print('get方法')
 8         return instance.__dict__[self.key]   #触发get方法,会返回字典的值
 9
10     def __set__(self, instance, value):
11         print('set方法')
12         if not isinstance(value,str):
13             print('你传入的类型不是字符串,错误')
14             return None  #return的作用就是终止这个属性字典,让他的值设置不进字典中。
15         instance.__dict__[self.key]=value     #存在p1的属性字典里面
16
17     def __delete__(self, instance):
18         print('delete方法')
19         instance.__dict__.pop(self.key)
20
21 class People:
22     name=Typed('name')                #name属性被Typed给代理了,t1._set_() self._set__()
23     def __init__(self,name,age,salary):
24         self.name=name
25         self.age=age
26         self.salary=salary
27
28 #正常的情况下__dict__里面有没有'name':'alex'
29 p1=People('alex',13,13.3)
30 print(p1.__dict__)   #触发set方法,得到的值是{'salary': 13.3, 'name': 'alex', 'age': 13}
31
32 #不正常的情况下,修改'name':213 不等于字符串,改成了int类型
33 p1=People(213,13,13.3)
34 print(p1.__dict__)   #触发set方法,得到的值是{'salary': 13.3, 'name': 'alex', 'age': 13}
35
36
37 ------------------------------------------------------------------
38 set方法
39 {'name': 'alex', 'age': 13, 'salary': 13.3}
40 set方法
41 你传入的类型不是字符串,错误
42 {'age': 13, 'salary': 13.3}

  方法二:用raise抛出异常的方式,判断他传入的值是不是字符串类型,(写死了,不灵活)

 1 #用抛出异常的方式,判断他传入的值是不是字符串类型
 2 class Typed:
 3     def __init__(self,key):
 4         self.key=key
 5
 6     def __get__(self, instance, owner):
 7         print('get方法')
 8         return instance.__dict__[self.key]   #触发get方法,会返回字典的值
 9
10     def __set__(self, instance, value):
11         print('set方法')
12         if not isinstance(value,str):  #判断是否是字符串类型
13             #方法一:return的方式
14             print('你传入的类型不是字符串,错误')
15             # return   #return的作用就是终止这个属性字典,让他的值设置不进字典中。
16             #方法二:
17             raise TypeError('你传入的类型不是字符串')
18             # ##用抛出异常的方式,判断他传入的值是不是字符串类型
19         instance.__dict__[self.key]=value     #存在p1的属性字典里面
20
21     def __delete__(self, instance):
22         print('delete方法')
23         instance.__dict__.pop(self.key)
24
25 class People:
26     name=Typed('name')                #name属性被Typed给代理了,t1._set_() self._set__()
27     def __init__(self,name,age,salary):
28         self.name=name
29         self.age=age
30         self.salary=salary
31
32 #正常的情况下__dict__里面有没有'name':'alex'
33 # p1=People('alex',13,13.3)
34 # print(p1.__dict__)   #触发set方法,得到的值是{'salary': 13.3, 'name': 'alex', 'age': 13}
35
36 #不正常的情况下,修改'name':213 不等于字符串,改成了int类型
37 p1=People(213,13,13.3)
38 print(p1.__dict__)   #触发set方法,得到的值是{'salary': 13.3, 'name': 'alex', 'age': 13}
39
40
41
42 ---------------------------------------------------------------
43 Traceback (most recent call last):
44 set方法
45 你传入的类型不是字符串,错误
46   File "E:/三期笔记/Python_s3/学习/day28/test.py", line 37, in <module>
47     p1=People(213,13,13.3)
48   File "E:/三期笔记/Python_s3/学习/day28/test.py", line 28, in __init__
49     self.name=name
50   File "E:/三期笔记/Python_s3/学习/day28/test.py", line 17, in __set__
51     raise TypeError('你传入的类型不是字符串')
52 TypeError: 你传入的类型不是字符串

  类型检测加强版

  示例:4:用raise抛出异常的方式,判断传入的值是什么类型,同时可以判断多个属性  (推荐写法)

 1 #用抛出异常的方式,判断他传入的值是什么类型  (不写死的方式,判断传入值的类型)
 2 class Typed:
 3     def __init__(self,key,expected_type):
 4         self.key=key
 5         self.expected_type=expected_type
 6
 7     def __get__(self, instance, owner):
 8         print('get方法')
 9         return instance.__dict__[self.key]   #触发get方法,会返回字典的值
10
11     def __set__(self, instance, value):
12         print('set方法')
13         if not isinstance(value,self.expected_type):
14              raise TypeError('%s 你传入的类型不是%s' %(self.key,self.expected_type)) #用抛出异常的方式,判断他传入的值是什么类型,同时可以判断多个属性的类型
15         instance.__dict__[self.key]=value     #存在p1的属性字典里面
16
17     def __delete__(self, instance):
18         print('delete方法')
19         instance.__dict__.pop(self.key)
20
21 class People:
22     name=Typed('name',str)  #name设置代理Typed
23     age=Typed('age',int)    #age设置代理Typed
24     def __init__(self,name,age,salary):
25         self.name=name    #alex传给代理,会触发set方法
26         self.age=age      #age传给代理,会触发set方法
27         self.salary=salary
28
29 #name是字符串,age是整型,salary必须是浮点数
30 #正确的方式
31 p1=People('alex',13,13.3)
32
33 #传入错误的类型,会判断传入值的类型
34 #name要求传入的srt,但这里传入的是整型,所以会报错,说你传入的不是srt类型
35 p1=People(213,13,13.3)

十八、__enter__  和 __ exit__

  1、操作文件推荐写法:

1 with open('a.txt') as f:
2   '代码块'

  2、上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__ 和__exit__方法

 1 class Open:
 2     def __init__(self,name):
 3         self.name=name
 4
 5     def __enter__(self):
 6         print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
 7         return self # f
 8     def __exit__(self, exc_type, exc_val, exc_tb):
 9         print('with中代码块执行完毕时执行我啊')
10
11
12 with Open('a.txt') as f:   #with语句,触发__enter__,返回值赋值给f
13     print('=====>执行代码块')
14     print(f,f.name)
15
16
17 --------------------------------------------------
18 出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量
19 =====>执行代码块
20 <__main__.Open object at 0x002AC750> a.txt
21 with中代码块执行完毕时执行我啊

  3、执行代码块

  __exit__()中的三个参数分别代表异常类型,异常值,追溯信息,with语句中的代码块出现异常,则with后的代码都是无法执行的

  没有异常的情况下,整个代码块运行完毕后去触发__exit__(),它的三个参数都会运行

 1 class Foo:
 2     def __init__(self, name):
 3         self.name = name
 4
 5     def __enter__(self):
 6         print('执行enter')
 7         return self  # 2、拿到的结果是self,并赋值给f
 8
 9     def __exit__(self, exc_type, exc_val, exc_tb):  # 4、触发__exit__,然后执行print()
10         print('执行exit')
11         print('-----',exc_type)
12         print('-----',exc_val)
13         print('-----',exc_tb)
14
15
16 with Foo('a.txt') as f:  # 1、with触发的是__enter__,拿到的结果是self并赋值给f;
17     print(f)  # 3、然后会执行with代码块,执行完毕后
18     print(assfsfdsfdsfdsfffsadfdsafdsafdsafdsafdsafdsafdsafdsad)
19     print(f.name)
20 print('000000000000000000000000000000000000000000000000000000')
21
22 ---------------------------------------------------------------------------------
23
24
25 Traceback (most recent call last):
26   File "E:/三期笔记/Python_s3/学习/day28/test.py", line 18, in <module>
27     print(assfsfdsfdsfdsfffsadfdsafdsafdsafdsafdsafdsafdsafdsad)
28 NameError: name 'assfsfdsfdsfdsfffsadfdsafdsafdsafdsafdsafdsafdsafdsad' is not defined
29 执行enter
30 <__main__.Foo object at 0x004F07F0>
31 执行exit
32 ----- <class 'NameError'>
33 ----- name 'assfsfdsfdsfdsfffsadfdsafdsafdsafdsafdsafdsafdsafdsad' is not defined
34 ----- <traceback object at 0x008300A8>

  4、有返回值

  如果__exit__() 返回值为True,那么异常会被清空,就好像啥都没有发生一样,with后的语句正常执行

 1 class Foo:
 2     def __init__(self,name):
 3         self.name=name
 4
 5     def __enter__(self):
 6         print('执行enter')
 7         return self
 8 # '''class、异常值、追踪信息'''
 9     def __exit__(self, exc_type, exc_val, exc_tb):   #2、有异常的时候,就会触发__exit__方法
10         print('执行exit')
11         print('====',exc_type)
12         print('====',exc_val)
13         print('====',exc_tb)
14         return True         #3、没有return True就会报错,如果有return True异常自己吃了,不报异常
15
16 with Foo('a.txt') as f:
17     print(f)
18     print(assfsfdsfdsfdsfffsadfdsafdsafdsafdsafdsafdsafdsafdsad)    #1、有异常的情况,他就会触发__exit__
19     print(f.name)           #不执行这行,直接打印下面那行
20 print('000000000000000000000000000000000000000000000000000000')     #4、最后打印这行
21
22 -----------------------------------------------------------------------
23
24 执行enter
25 <__main__.Foo object at 0x003907F0>
26 执行exit
27 ==== <class 'NameError'>
28 ==== name 'assfsfdsfdsfdsfffsadfdsafdsafdsafdsafdsafdsafdsafdsad' is not defined
29 ==== <traceback object at 0x023E00A8>
30 000000000000000000000000000000000000000000000000000000

  总结

  with obj as f:
    '代码块'

  1、with obj ——》 触发obj.__enter__(),拿到返回值

  2、as f ————》 f = 返回值

  3、with obj as f 等同于 f = obj.__enter__()

  4、执行代码块

  一、没有异常的情况下,整个代码块运行完毕后触发__exit__,它的三个参数都为None

  二、有异常的情况下,从异常出现的位置直接触发__exit__

    a:如果__exit__的返回值为True,代表吞掉了异常

    b:如果__exit__的返回值不为True,代表吐出了异常

    c:__exit__的运行完毕就代表整个with语句的执行完毕

  用途:

    1、使用withhi把语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无需手动干预。

    2、在需要管理一些资源,比如:文件,网络连接(TCP协议建连接、传输数据、关连接)和锁(进程,线程)的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关心这个问题。

十九、类的装饰器

  示例1:类的装饰器的基本原理

 

 

转载于:https://www.cnblogs.com/JerryZao/p/8797890.html

Python-面向对象(进阶)相关推荐

  1. Python面向对象进阶和socket网络编程

    写在前面 为什么坚持?想一想当初: 一.面向对象进阶 - 1.反射补充 - 通过字符串去操作一个对象的属性,称之为反射: - 示例1: class Chinese:def __init__(self, ...

  2. Python面向对象进阶与异常、模块以及包管理

    这一篇是面向对象的进阶部分,主要还是面向对象的封装,继承,多态方面的讲解,后面的部分是讲解python异常和模块以及包的部分. 目录 一.Python中的继承 1.什么是继承 2.继承的基本语法 3. ...

  3. Python面向对象进阶及类成员

    再次了解多继承 先来一段代码 #!/usr/bin/env python # _*_ coding:utf-8 _*_ class A:    def bar(self):        print( ...

  4. Python 面向对象进阶

    阅读目录 构造方法.析构方法.__str__ 方法 构造方法 析构方法 __str__ 方法 类的成员 字段(变量) 类变量和实例变量(静态字段 和 字段) 公有/私有 类变量(静态字段) 公有/私有 ...

  5. python面向对象进阶

    property 内置装饰器函数 只在面向对象中使用 from math import piclass Circle:def __init__(self, r):self.r = r@property ...

  6. 【Python面向对象进阶④】——定制类

    Python中的魔法方法 @ author: Flyme awei 方法名 说明 __str__ 用于返回对象的描述 __iter__ 使类可以迭代 __getitem__ 按照下标获取类元素,例如l ...

  7. 定制类【Python面向对象进阶四】

    Python中的魔法方法 @ author: Flyme awei 方法名 说明 __str__ 用于返回对象的描述 __iter__ 使类可以迭代 __getitem__ 按照下标获取类元素,例如l ...

  8. python——面向对象进阶之新增属性和方法

    例如:定义一个类 1.可不可以动态的给对象p赋予一个新的对象属性 1.1 修改实例属性 p.name = 'jam' print(p.name) 1.2 给对象赋予一个新的属性(实例属性) p.sex ...

  9. 【Python】Python面向对象详解

    Python面向对象 Python是一种面向对象的编程语言,因此它支持面向对象编程(OOP).面向对象编程是一种程序设计方法,它将数据和行为打包成对象.对象是类的实例,而类是具有相似属性和行为的一组对 ...

  10. Python之面向对象进阶

    Python之面向对象进阶 进阶有:Python 类的成员.成员修饰符.类的特殊成员. 一.类的成员 类的成员可以分为三大类:字段.方法和属性. 注:所有成员中,只有普通字段的内容保存对象中,即:根据 ...

最新文章

  1. 获取长度length_lab、labE、la、laE、ll、llE 钢筋锚固搭接长度6项参数的相互关系...
  2. 设置路径是服务器上的文件,设置服务器文件路径
  3. VB 长整型和字节数组的转换问题 (LongByte)
  4. sql count用法_SQL是一门手艺
  5. 实验4 贪心法(作业调度问题)
  6. 为什么python删除不了_为什么python的imp.reload()不会删除旧的类和函数?
  7. 《ISO20000-12011 认证合格判定基础》(证书样例子+认证文档+录音下载)
  8. android设备连接打印机,【Android快讯】教你通过Android设备直接连接打印机打印文件...
  9. 【luogu3403】跳楼机 [同余最短路]
  10. 【深度学习之美】一入侯门“深”似海,深度学习深几许(入门系列之一)
  11. linux时间转换及比较
  12. 程序员之路:护眼豆沙绿颜色值
  13. CSDN的迷你博客为什么冷冷清清?
  14. 亚马逊中国站获取全部商品分类
  15. ES6中派生类的Super为什么一定要在使用this前调用
  16. 100亿资助!施一公领衔的“新基石研究员项目”,正式发布!
  17. VisualFreeBasic:VisualBasic6望尘莫及之变量初始
  18. nslookup默认服务器修改,Windows Server 2008 R2 域控服务器运行nslookup命令默认服务器显示 UnKnown...
  19. C++计算某个数的所有因数
  20. 联想Idea Pad Y430 开启VT

热门文章

  1. android 炫酷3d主页,五款超酷安卓手机3D桌面软件合辑推荐
  2. 云计算发展备受瞩目的五大方向
  3. pg_restore使用
  4. 怎么对MySQL数据库操作大数据?这里有思路
  5. XML文档的使用方法
  6. bootstrap 栅格系统实现类似table跨行
  7. epoll的一个使用例子
  8. 说说Java 7中的模块系统基本概念
  9. 图解算法之排序算法(3)——插入排序
  10. Python检验某个字符(串)是否属于另一个字符串