python的装饰器、with、上下文管理器等简单的记录

目录

装饰器

大致流程

with与上下文管理器

上下文管理器

eval()函数的使用


装饰器

参考这里,非常nice的文章

引用他的话:

写代码要遵循开放封闭原则,简单来说,已经实现的功能代码内部不允许被修改,但外部可以被扩展。装饰器可以在不修改原有代码的情况下,为被装饰的对象增加新的功能或者附加限制条件或者帮助输出

大致流程

# 首先定义装饰器
def decorator(arg):
    
    return func


# 调用装饰器
@decorator
def aim_function()

大致的核心的思想是 将需要装饰的目标作为参数传入到装饰器中,装饰器的返回值赋予被修饰的目标。最终,目标可以通过装饰器进行扩展。

需要注意:在执行代码时会按顺序遇到 @decorator 会执行装饰器中的过程一次,而且目标aim_function()最终会指向装饰器的返回值的内存,所以,一般装饰器的返回值会是一个扩展的在其内部封装的函数

如果多个装饰器修饰一个目标,则按顺序应为从外到里,扩展的过程应从后往前看,aim_func先被@decorator3扩展,在其基础上被@decorator2包装,最后在其结果上被@decorator1包装然后返回。其实就是按参数的传递顺序,从下往上一次作为参数进行传递。

@decorator1
@decorator2
@decorator3
def aim_func()

with与上下文管理器

具体请参考这里

上述文章写的非常nice。一般的用法,举例

# 类里面
class Object:
    
    def __init__(self,)

    def __enter__(self):
        
        return object

    def __exit__(self, exc_type, exc_val, exc_tb):



    def read(self):  # 自定义的方法



with Object() as o:   #  随便写的
    o.read()

# 或者
with Object():

流程:
1、创建Object()实例化对象,调用__enter__中的方法,将其返回值赋给o

2、执行 with 下的语句

3、最后由该实例化对象中的__exit__收尾

因此, __enter__ 和 __exit__ 是必须在 类对象里存在的。 如果没有,则报错,如下:

AttributeError: __exit__

Process finished with exit code 1

__exit__中的可选参数如下:

def __exit__(self, exc_type, exc_val, exc_tb):

# exc_type  异常值类型
# exc_val   异常值
# exc_tb    异常值的回溯栈

正常运行时,它们的值都为 None

class Open:

    def __init__(self, filename, mode='r', encoding=None):
        self.filename = filename
        self.mode = mode
        self.encoding = encoding

    def __enter__(self):
        print('开始执行__enter__')
        return "来,小亮,给他整个活🐯"

    def read(self):
        print('以{}模式打开文件{}'.format(self.mode, self.filename))

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('最后执行 __exit__')
        print('草!走!忽略ጿ ኈ ቼ ዽ ጿ')
        print(exc_type)
        print(exc_val)
        print(exc_tb)

with Open('1.txt') as f:
    print(f)


# 输出

开始执行__enter__
来,小亮,给他整个活🐯
最后执行 __exit__
草!走!忽略ጿ ኈ ቼ ዽ ጿ
None
None
None

如果出现异常,那么异常语句之后的将不会执行并被跳过,直接执行 __exit__,

class Open:

    def __init__(self, filename, mode='r', encoding=None):
        self.filename = filename
        self.mode = mode
        self.encoding = encoding

    def __enter__(self):
        print('开始执行__enter__')
        return "来,小亮,给他整个活🐯"

    def read(self):
        print('以{}模式打开文件{}'.format(self.mode, self.filename))

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('最后执行 __exit__')
        print('草!走!忽略ጿ ኈ ቼ ዽ ጿ')
        print(exc_type)
        print(exc_val)
        print(exc_tb)
        return True

with Open('1.txt') as f:
    print(f)
    1/0
    print('沈阳等你嗷')

print('我们就烩烩你')

# 输出
开始执行__enter__
来,小亮,给他整个活🐯
最后执行 __exit__
草!走!忽略ጿ ኈ ቼ ዽ ጿ
<class 'ZeroDivisionError'>
division by zero
<traceback object at 0x00000194AD16A788>
我们就烩烩你

Process finished with exit code 0

可以看到 “沈阳等你嗷” 并没有打印, 而 with 之外的 我们烩烩你 执行了。其中__exit__返回 True 则表示程序不报错正常执行,将异常吞掉继续执行其它语句。

若不设置返回值 为True,程序会报错,并崩溃停止执行

# 不设置 return True 打印
Traceback (most recent call last):
  File "***", line 31, in <module>
    1/0
ZeroDivisionError: division by zero
开始执行__enter__
来,小亮,给他整个活🐯
最后执行 __exit__
草!走!忽略ጿ ኈ ቼ ዽ ጿ
<class 'ZeroDivisionError'>
division by zero
<traceback object at 0x0000025ADBFAA788>

Process finished with exit code 1

至于设置了返回值为True,后面的 “沈阳等你嗷” 没有打印,是因为在执行 __exit__ 后with语块流程就结束了。遇到异常 则 在异常处 直接提前 跳入执行 __exit__,下面的语句就被跳过了。

所以,根据这个原理,可以设置备选方案,如果一个方案可能遇到执行不通的状况,则这时可以跳过这个方案,执行其它方案。

这个跟

try:

except:

 很像。

上下文管理器

具体的参考上述的 with 参考的文章。那个利用他来做 装饰器。

在代码中遇到的

class Profile(contextlib.ContextDecorator):
    # YOLOv5 Profile class. Usage: @Profile() decorator or 'with Profile():' context manager
    def __init__(self, t=0.0):
        self.t = t
        self.cuda = torch.cuda.is_available()

    def __enter__(self):
        self.start = self.time()
        return self

    def __exit__(self, type, value, traceback):
        self.dt = self.time() - self.start  # delta-time
        self.t += self.dt  # accumulate dt

    def time(self):
        if self.cuda:
            torch.cuda.synchronize()
        return time.time()

调用

dt = (Profile(), Profile(), Profile())

with dt[0]:


with dt[1]:


with dt[2]:

计算每一步的时间,累计总的时间。

eval()函数的使用

参考这里

object = eval(str)

执行 str字符串中的内容,并赋给object。 str可以是函数名,也可以是类方法的名称 

=========================================================================

那一脚踢出了盛夏~

  • 20
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Python中,上下文管理器是一种处理资源的方式,它能够自动分配并且释放资源,比如打开和关闭文件、数据库连接等。上下文管理器通常使用with语句来实现,保证了代码块执行完毕后,资源被释放。Python提供了两种实现上下文管理器的方式:使用类和使用装饰器。 使用类实现上下文管理器时,需要定义一个类,并且实现`__enter__()`和`__exit__()`方法。`__enter__()`方法会在进入代码块前被调用,它负责资源的分配;`__exit__()`方法则会在代码块执行完成后被调用,负责资源的释放。 以下是一个简单的示例: ```python class MyContext: def __init__(self, resource): self.resource = resource def __enter__(self): print("Entering context...") return self.resource def __exit__(self, exc_type, exc_val, exc_tb): print("Exiting context...") self.resource.close() with MyContext(open("file.txt", "w")) as f: f.write("Hello World!") ``` 使用装饰器实现上下文管理器时,需要定义一个函数,并且使用`@contextlib.contextmanager`装饰器修饰它。这个函数需要使用`yield`语句将控制权传递给with语句块,然后在finally块中释放资源。 以下是一个简单的示例: ```python from contextlib import contextmanager @contextmanager def my_context(resource): try: print("Entering context...") yield resource finally: print("Exiting context...") resource.close() with my_context(open("file.txt", "w")) as f: f.write("Hello World!") ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

匿名的魔术师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值