Python基础(十一)-面向对象四

一、上下文管理协议

1.1、什么叫上下文管理协议?

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

即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法

with语句小结

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.2、方法使用

class Open:
    def __init__(self,name):
        self.name=name

    def __enter__(self):
        print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('with中代码块执行完毕时执行我啊')


with Open('a.txt') as f:  #触发__enter__方法
    print('=====>执行代码块')
    print(f,f.name)  #<__main__.Open object at 0x0000022813E55C88> a.txt

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

class Open:
    def __init__(self,name):
        self.name=name

    def __enter__(self):
        print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('with中代码块执行完毕时执行我啊')
        print(exc_type)
        print(exc_val)
        print(exc_tb)


with Open('a.txt') as f:
    print('=====>执行代码块')
    raise AttributeError('异常产生')
print('0'*100) #------------------------------->不会执行

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

class Open:
    def __init__(self,name):
        self.name=name

    def __enter__(self):
        print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('with中代码块执行完毕时执行我啊')
        print(exc_type)    #<class 'AttributeError'>
        print(exc_val)     #产生异常
        print(exc_tb)      #<traceback object at 0x000001E54419AF08>
        return True


with Open('a.txt') as f:
    print('=====>执行代码块')
    raise AttributeError('产生异常')
print('0'*100) #------------------------------->会执行

模拟open:

class Open:
    def __init__(self,filepath,mode='r',encoding='utf-8'):
        self.filepath=filepath
        self.mode=mode
        self.encoding=encoding

    def __enter__(self):
        print('enter')
        self.f=open(self.filepath,mode=self.mode,encoding=self.encoding)  #拿到文件句柄
        return self.f

    def __exit__(self, exc_type, exc_val, exc_tb):
        # print('exit')
        self.f.close()
        return True
    def __getattr__(self, item):
        return getattr(self.f,item)

with Open('a.txt','w') as f:  #f==open(self.filepath,mode=self.mode,encoding=self.encoding)
    print(f)                  #<_io.TextIOWrapper name='a.txt' mode='w' encoding='utf-8'>
    f.write('aaaaaa')
    f.wasdf #抛出异常,交给__exit__处理

1.3、上下文管理用途

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

2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处

二、描述符

2.1、什么是描述符?

描述符本质就是一个新式类,在这个新式类中,至少实现__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议
__get__():调用一个属性时,触发
__set__():为一个属性赋值时,触发
__delete__():采用del删除属性时,触发

class Foo: #在python3中Foo是新式类,它实现了三种方法,这个类就被称作一个描述符
    def __get__(self, instance, owner):
        pass
    def __set__(self, instance, value):
        pass
    def __delete__(self, instance):
        pass

2.2、描述符是干什么的?

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

#描述符Str
class Str:
    def __get__(self, instance, owner):
        print('Str调用')
    def __set__(self, instance, value):
        print('Str设置...')
    def __delete__(self, instance):
        print('Str删除...')

#描述符Int
class Int:
    def __get__(self, instance, owner):
        print('Int调用')
    def __set__(self, instance, value):
        print('Int设置...')
    def __delete__(self, instance):
        print('Int删除...')

class People:
    name=Str()
    age=Int()
    def __init__(self,name,age): #name被Str类代理,age被Int类代理,
        self.name=name
        self.age=age


p1=People('alex',18)  #触发str类的__set__,触发int类的__set__
print("========")

#描述符Str的使用
print(p1.name)  #Str调用 None
p1.name='egon'
del p1.name

#描述符Int的使用
p1.age   #Int调用
p1.age=18  #Int设置...
del p1.age  #Int删除...

print(p1.__dict__)  #{}
print(People.__dict__)  #{'__init__': <function People.__init__ at 0x000001714E4CE620>, 'age': <__main__.Int object at 0x000001714E4D46D8>, '__module__': '__main__', 'name': <__main__.Str object at 0x000001714E4D46A0>, '__dict__': <attribute '__dict__' of 'People' objects>, '__doc__': None, '__weakref__': <attribute '__weakref__' of 'People' objects>}


#补充
print(type(p1) == People) #True,type(obj)其实是查看obj是由哪个类实例化来的
print(type(p1).__dict__ == People.__dict__) #True

猜你喜欢

转载自www.cnblogs.com/hujinzhong/p/11499088.html