chapter9.3、可调用对象,上下文管理

可调用对象

函数也是对象,函数可以调用,对象加上括号,就是对象调用自己的__call__方法,函数也是可调用对象

def foo():
    print(foo.__module__,foo.__name__)
foo()
#等价于
foo.__call__()

都返回__main__ foo

__call__      类中定义的方法,使实例可以像函数一样调用

格式化返回坐标的点

class Point:
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def __call__(self, *args, **kwargs):
        return "<Point {}:{}>".format(self.x,self.y)

p = Point(4,2)
print(p)##返回实例的对象
print(p())##返回<Point 4:2>,调用实例,调用了__call__

加法器

class Adder:
    def __call__(self,*args):
        ret = 0
        for x in args:
            ret += x
        self.ret = ret
        return ret

adder=Adder()
print(adder(1,2,3))
print(adder.ret)

斐波那契数列的实现

class Fib:
    def __init__(self):
        self.items = [0,1,1]

    def __call__(self,n):
        if n < 0:
            raise IndexError('Wrong Index')
        if n < len(self.items):
            return self.items[n]

        for i in range(n-len(self.items)+1):
            self.items.append(self.items[-1]+self.items[-2])
        return self.items[n]

fib = Fib()
print(fib(5))

使用类来实现斐波那契数列较为合适,还可以缓存,检索

上下文管理

文件IO操作可以对文件对象使用上下文管理,使用with...as语法

对类使用上下文管理:

  3.5之前open一个class,返回AttributeError:__exit__

  3.6之后返回AttributeError:__enter__

当一个对象同时实现了__enter__和__exit__,就属于上下文管理对象

定义__enter__,进入对象相关的上下文,如果存在,with后又有as,就会将返回值绑定到as后的变量上

__exit__,退出于此对象相关的上下文,exit里加关闭文件之类的操作

进出with,打开调enter,结束调exit,

import time
class Point:
    def __init__(self):
        print('init')
        
    def __enter__(self):
        print("enter")
        return 100
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit')

with Point() as f:
    print('-'*30)
    print(f)
    time.sleep(5)
    print("_"*30)

print('____________end____________')

返回中可以看到执行顺序,with后边的实例先创建,调用__init__方法,后with打开调用__enter__,

执行with中的语句,退出with时再调用__exit__,而且退出时无论上方如何执行都一定会被with清除占用的资源。

with可以开启一个上下文运行环境,在执行前做一些准备工作,执行后做一些收尾工作

with Point() as f:
    raise Exception('error')
    print('123')

通过上个实验,可以看到,即使是异常的抛出都无法阻止with执行__exit__

import sys
with Point() as f:
    sys.exit(100)
    print('123')
print('outer')

这个例子更极端,直接退出当前解释器,也不会阻止with执行清理

所以,上下文管理是安全的

with语句

class Point:
    def __init__(self):
        print('init')

    def __enter__(self):
        print('enter')def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit')

p = Point()
with p as f:
    print(p==f)###返回False,as要求__enter__返回值赋给f
    print('~~~~~')

以上代码缺少__enter__的返回值,所以不等

class Point:
    def __init__(self):
        print('init')

    def __enter__(self):
        print('enter')
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit')

p = Point()
with p as f:
    print(p==f)
    print('~~~~~')

__enter__方法返回值就是上下文中使用的对象,with语法会把它的返回值赋给as字句的变量

__exit__方法有三个参数,(self,exc_type,exc_value,traceback)

 这三个参数都与异常有关,如果没有异常这三个参数就是None。

如果有异常,参数就有意义

exc_type表示异常类型,exc_value,表示异常的值,traceback异常追踪的信息

__exit__方法返回一个等效的True的值,则压制异常,否则抛出异常

class Point:
    def __init__(self):
        print('init')

    def __enter__(self):
        print('enter')
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(exc_type)##类型,此处返回Exception
        print(exc_val)##此处返回with中返回的异常值,"what's wrong"
        print(exc_tb)##返回异常追踪<traceback object at 地址>
        print('exit')
        return True###为等效True都会压制异常
    
p = Point()
with p as f:
    raise Exception("what's wrong")
    print('do sth')
    
print('outer')

enter不可加参数

exit中traceback

exit 的return为等效bool值True时,可以压制异常,为False时不压制

资源申请和资源释放

安全性

装饰器,类成为装饰器

inspcct看类的签名

多个装饰器的顺序会有影响,???留问题了

wrapper复习

应用场景,增强功能类似装饰器,

资源管理,链接管理’

权限验证

contextmanager

猜你喜欢

转载自www.cnblogs.com/rprp789/p/9683844.html