标签: contextmanager

带参数和不带参数的上下文装饰器

我想将上下文装饰器与带参数或不带参数的可能性结合起来。

让我们从一个可以使用参数和不使用参数的装饰器开始,例如:

import functools


def decorator(func=None, *, label=""):
    if func is None:
        return functools.partial(decorator, label=label)

    @functools.wraps(func)
    def wrap(*args, **kwargs):
        result = func(*args, **kwargs)
        print(f"RESULT {label}: {result}")
        return result

    return wrap


if __name__ == "__main__":

    @decorator(label="with arguments")
    def dec_args():
        return 1

    @decorator
    def dec_no_args():
        return 0

    dec_args()
    dec_no_args()
Run Code Online (Sandbox Code Playgroud)

还有ContextDecorator可以用作上下文管理器或装饰器的:

from contextlib import ContextDecorator

class ctxtdec(ContextDecorator):
    def __init__(self, label:str=""):
        self.label = label
        print(f"initialized {self.label}")

    def __enter__(self):
        print(f"entered {self.label}")

    def __exit__(self, exc_type, exc_value, traceback):
        print(f"exited {self.label}")

if __name__ == "__main__":
    def …
Run Code Online (Sandbox Code Playgroud)

python decorator contextmanager

5
推荐指数
1
解决办法
1692
查看次数

重用现有的上下文管理器作为 pytest 固定装置

我有一个多个测试所需的现有上下文管理器。with我认为最好从这个上下文管理器中制作一个固定装置,并用@pytest.mark.usefixtures("my_fixture").

我可以将上下文管理器重新实现为固定装置,但这似乎是重复的代码。所以我想在新的装置中引用原始的上下文管理器。

这就是我所拥有的:

import my_context_manager

@pytest.fixture
def my_fixture(arg1, arg2):

    with my_context_manager(arg1, arg2) as c:
        yield c
Run Code Online (Sandbox Code Playgroud)

这是将现有上下文管理器转换为固定装置的适当方法吗?

我应该提到,我知道contextlib.ContextDecorator编写一个可以用作装饰器的上下文管理器。但我的上下文管理器需要参数,而当它们出现在像@my_context_decorator(arg1, arg2).

python fixtures contextmanager pytest

5
推荐指数
1
解决办法
2313
查看次数

如何使用上下文管理器支持可选的 stdin/stdout?

假设我想实现一个具有以下签名的 Python 脚本:

myscript.py INPUT OUTPUT
Run Code Online (Sandbox Code Playgroud)

...其中INPUT和分别OUTPUT代表脚本将读取和写入的文件的路径。

用于实现具有此类签名的脚本的代码可能具有以下构造:

with open(inputarg, 'r') as instream, open(outputarg, 'w') as outstream:
    ...
Run Code Online (Sandbox Code Playgroud)

...这里的inputarg和变量保存通过其和命令行参数outputarg传递给脚本的文件路径(字符串) 。INPUTOUTPUT


到目前为止没有什么特别或不寻常的事情。

但现在,假设对于脚本的版本 2,我想为用户提供-为其一个(或两个)参数传递特殊值的选项,以指示脚本应分别读取stdin和写入stdout

换句话说,我希望以下所有形式都能产生相同的结果:

myscript.py INPUT OUTPUT
myscript.py   -   OUTPUT  <INPUT
myscript.py INPUT   -             >OUTPUT
myscript.py   -     -     <INPUT  >OUTPUT
Run Code Online (Sandbox Code Playgroud)

现在,with之前的说法已经不再适用。一方面,表达式open('-', 'r')oropen('-', 'w')都会引发异常:

FileNotFoundError: [Errno 2] No such file or directory: '-'
Run Code Online (Sandbox Code Playgroud)

我无法想出一种方便的方法来扩展with上面基于 …

python stdin stdout contextmanager

5
推荐指数
1
解决办法
858
查看次数

Python:使用 ExitStack 避免多个 with 语句的最佳方法

我有以下代码来使用 ExitStack 而不是 with 语句。

from contextlib import contextmanager
from contextlib import ExitStack
from tempfile import NamedTemporaryFile


@contextmanager
def myfile():
    temp_file = NamedTemporaryFile(suffix='.txt')
    temp_file.seek(0)
    yield temp_file
    os.unlink(temp_file.name)


with ExitStack() as stack:
    files = []
    for idx in range(5):
        files.append(stack.enter_context(myfile()))
    # do something with the files
Run Code Online (Sandbox Code Playgroud)

上面的代码给出了 5 个错误消息,如下所示

FileNotFoundError: [Errno 2] No such file or directory: '/tmp/tmpbupwinzt.txt'
Run Code Online (Sandbox Code Playgroud)

我是否以错误的方式使用 ExitStack?做上述事情的正确方法是什么。

注意:我无法更改myfile()功能,但可以更改其余代码。

python with-statement contextmanager

5
推荐指数
1
解决办法
5482
查看次数

带括号的上下文管理器在 python 3.9 中有效,但在 3.8 中无效

所以我有一个简单的声明示例with。它适用于 Python 3.8 和 3.9:

class Foo:
    def __enter__(self, *args):
        print("enter")

    def __exit__(self, *args):
        print("exit")

with Foo() as f, Foo() as b:
    print("Foo")
Run Code Online (Sandbox Code Playgroud)

输出(如预期):

enter
enter
Foo
exit
exit
Run Code Online (Sandbox Code Playgroud)

但如果我像这样添加括号,它只适用于 Python 3.9:

class Foo:
    def __enter__(self, *args):
        print("enter")

    def __exit__(self, *args):
        print("exit")

with (Foo() as f, Foo() as b):
    print("Foo")
Run Code Online (Sandbox Code Playgroud)

3.8 中的输出:

  File "foo.py", line 8
    with (Foo() as f, Foo() as b):
                ^
SyntaxError: invalid syntax
Run Code Online (Sandbox Code Playgroud)

我知道,我可以删除括号,但我不明白为什么它首先在 Python 3.9 中工作。我找不到相关的变更日志。

python with-statement contextmanager python-3.x python-3.9

5
推荐指数
1
解决办法
1068
查看次数

如何将 contextlib.contextmanager 与类方法一起使用?

请参阅下面的 Python 3.10 代码片段:

import contextlib

class Foo:
    @contextlib.contextmanager
    @classmethod
    def state(cls):
        try:
            yield
        finally:
            pass

with Foo.state():
    pass
Run Code Online (Sandbox Code Playgroud)

它抛出一个TypeError

Traceback (most recent call last):
  File "/path/to/code/play/quick_play.py", line 12, in <module>
    with Foo.state():
  File "/path/to/.pyenv/versions/3.10.5/lib/python3.10/contextlib.py", line 281, in helper
    return _GeneratorContextManager(func, args, kwds)
  File "/path/to/.pyenv/versions/3.10.5/lib/python3.10/contextlib.py", line 103, in __init__
    self.gen = func(*args, **kwds)
TypeError: 'classmethod' object is not callable
Run Code Online (Sandbox Code Playgroud)

可以用classmethod来装饰吗contextlib.contextmanager?如果是的话,该怎么做?

python class-method contextmanager

5
推荐指数
1
解决办法
2107
查看次数

上下文管理器:__init__ 方法内的错误处理

一些背景

我正在使用一个包,它允许您使用文件中存储的信息来计算有关行星的一些信息(例如它们的速度或位置)。该包包含加载和卸载文件的方法,因此其基本用法如下所示:

load(["File_1", "File_2"])

try:

    function()

finally:

    unload(["File_1", "File_2"])
Run Code Online (Sandbox Code Playgroud)

由于这是上下文管理器实用程序的教科书示例,并且该包缺少一个,因此我正在编写自己的示例。

class file_manager:

    def __init__(self, file_list) -> None:

        self.file_list = file_list

        load(self.file_list)

        return None

    def __enter__(self) -> None:

        return None

    def __exit__(self, exc_type, exc_value, traceback) -> None:

        unload(self.file_list)

        return None
Run Code Online (Sandbox Code Playgroud)

使用新的上下文管理器,前面的示例可以重写如下:

with file_manager(["File_1", "File_2"]):

    function()
Run Code Online (Sandbox Code Playgroud)

该方法保证如果出现错误__exit__,文件仍然会被卸载。function

我的问题

load函数逐个加载文件,而不首先检查所有文件是否可用。因此,如果File_1存在,但File_2不存在,File_1则会被加载,并且在加载时会引发异常File_2。根据 python 文档:

with 语句保证如果__enter__()方法返回且没有错误,则__exit__()始终会调用 then。

因此,在前面的情况下,程序的执行将在没有File_2被卸载的情况下结束。

我在寻找什么

我显然可以通过try...except在方法中使用一个子句来解决这个问题__init__()

def __init__(self, …
Run Code Online (Sandbox Code Playgroud)

python contextmanager

5
推荐指数
1
解决办法
520
查看次数

为什么我的contextmanager函数不能像python中的contextmanager类一样工作?

在我的代码中,我需要能够正确地打开和关闭设备,因此需要使用上下文管理器.虽然上下文管理器通常被定义为带有__enter____exit__方法的类,但似乎还有可能装饰一个与上下文管理器一起使用的函数(参见最近的帖子另一个很好的例子).

在下面(工作)的代码片段中,我实现了两种可能性; 一个只需要将注释行与另一个交换:

import time
import contextlib

def device():
    return 42

@contextlib.contextmanager
def wrap():
    print("open")
    yield device
    print("close")
    return

class Wrap(object):
    def __enter__(self):
        print("open")
        return device
    def __exit__(self, type, value, traceback):
        print("close")


#with wrap() as mydevice:
with Wrap() as mydevice:
    while True:
        time.sleep(1)
        print mydevice()
Run Code Online (Sandbox Code Playgroud)

我尝试的是运行代码并停止它CTRL-C.当我Wrap在上下文管理器中使用该类时,该__exit__方法被调用为已解决(文本'close'在终端中打印),但是当我尝试使用该wrap函数时,文本'close'不会打印到终奌站.

我的问题:代码片段是否存在问题,我是否遗漏了某些内容,或者为什么print("close")没有使用装饰函数调用该行?

python contextmanager python-2.7

4
推荐指数
1
解决办法
1498
查看次数

如何使用列表推导与可变数量的文件名列表?

给出文件名列表filenames = [...].

是否可能重写I/O安全的下一个列表理解:[do_smth(open(filename, 'rb').read()) for filename in filenames]?使用with语句,.close方法或其他东西.

另一个问题是:是否可能为下一个代码编写I/O安全列表理解?

results = []
for filename in filenames:
   with open(filename, 'rb') as file:
      results.append(do_smth(file.read()))
Run Code Online (Sandbox Code Playgroud)

python file-io list-comprehension contextmanager python-3.x

4
推荐指数
1
解决办法
119
查看次数

`with return .. return`无法访问的代码?

PyCharm警告这段代码,说最后一次返回是无法访问的:

def foo():
    with open(...):
        return 1
    return 0
Run Code Online (Sandbox Code Playgroud)

我希望如果open()失败,第二次返回将会执行.谁是对的?

python with-statement contextmanager pycharm

4
推荐指数
1
解决办法
588
查看次数