标签: contextmanager

contextlib.nested的替代方法,具有可变数量的上下文管理器

我们有代码根据运行时参数调用可变数量的上下文管理器:

from contextlib import nested, contextmanager

@contextmanager
def my_context(arg):
    print("entering", arg)
    try:
        yield arg
    finally:
        print("exiting", arg)

def my_fn(items): 
    with nested(*(my_context(arg) for arg in items)) as managers:
        print("processing under", managers)

my_fn(range(3))
Run Code Online (Sandbox Code Playgroud)

但是,contextlib.nested自Python 2.7以来已弃用:

DeprecationWarning: With-statements now directly support multiple context managers
Run Code Online (Sandbox Code Playgroud)

Python'with '语句中的多个变量的答案表明contextlib.nested存在一些"令人困惑的容易出错的怪癖",但建议使用多管理器with语句的替代方法不适用于可变数量的上下文管理器(并且还会破坏向后兼容性) ).

是否有任何替代品contextlib.nested不被弃用,并且(最好)没有相同的错误?

或者我应该继续使用contextlib.nested并忽略警告?如果是这样,我是否应该计划contextlib.nested在将来的某个时间将其删除?

python with-statement deprecated contextmanager

25
推荐指数
2
解决办法
6172
查看次数

在上下文管理器中__init__ vs __enter__

据我了解,__init__()__enter__()上下文管理的方法调用一次每个,一个接一个,不留下任何机会之间执行任何其他代码.将它们分成两种方法的目的是什么,我应该将它们放入每种方法中?

编辑:对不起,没注意文档.

编辑2:实际上,我感到困惑的原因是因为我在想@contextmanager装饰师.使用创建的上下文管理器@contextmananger只能使用一次(第一次使用后生成器将耗尽),因此通常使用构造函数内部with语句编写; 如果这是使用with陈述的唯一方法,我的问题就有意义了.当然,实际上,情境管理者比@contextmanager可以创造的更为笼统; 特别是上下文管理器通常可以重用.我希望这次能做对吗?

python contextmanager python-3.x

24
推荐指数
2
解决办法
1万
查看次数

在上下文管理器中捕获异常__enter __()

__exit__()即使存在异常,是否可以确保调用该方法__enter__()

>>> class TstContx(object):
...    def __enter__(self):
...        raise Exception('Oops in __enter__')
...
...    def __exit__(self, e_typ, e_val, trcbak):
...        print "This isn't running"
... 
>>> with TstContx():
...     pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __enter__
Exception: Oops in __enter__
>>> 
Run Code Online (Sandbox Code Playgroud)

编辑

这是我能得到的尽可能接近......

class TstContx(object):
    def __enter__(self):
        try:
            # __enter__ code
        except Exception as e
            self.init_exc = e

        return self

    def __exit__(self, e_typ, e_val, trcbak): …
Run Code Online (Sandbox Code Playgroud)

python exception with-statement contextmanager python-2.7

23
推荐指数
3
解决办法
2万
查看次数

多行上的Python嵌套上下文管理器

在Python 2.6中,我们使用以下方式格式化嵌套上下文管理器:

with nested(
    context1,
    context2
) as a, b:
    pass
Run Code Online (Sandbox Code Playgroud)

从Python 2.7开始,nested不推荐使用.我在一行上看到了很多关于多个上下文管理器的例子,但我找不到允许它们在多行上的语法.你会怎么做?

# That's working fine
with context1 as a, context2 as b:
    pass

# But how do we make it multine?
# These are not working
with (
    context1,
    context2
) as a, b:
    pass

with context1 as a,
    context2 as b:
    pass
Run Code Online (Sandbox Code Playgroud)

python with-statement contextmanager

23
推荐指数
2
解决办法
9018
查看次数

Pythonic为类所拥有的对象组成上下文管理器的方法

对于某些任务,通常需要多个具有明确释放资源的对象 - 例如,两个文件; 当任务是使用嵌套with块的函数的本地任务时,这很容易完成,或者 - 甚至更好 - with具有多个with_item子句的单个块:

with open('in.txt', 'r') as i, open('out.txt', 'w') as o:
    # do stuff
Run Code Online (Sandbox Code Playgroud)

OTOH,当这些对象不仅仅是函数作用域的本地对象,而是由类实例拥有 - 换句话说,上下文管理器如何构成时,我仍然很难理解它应该如何工作.

理想情况下,我想做的事情如下:

class Foo:
    def __init__(self, in_file_name, out_file_name):
        self.i = WITH(open(in_file_name, 'r'))
        self.o = WITH(open(out_file_name, 'w'))
Run Code Online (Sandbox Code Playgroud)

并有Foo自己变成上下文管理,处理io,这样,当我做

with Foo('in.txt', 'out.txt') as f:
    # do stuff
Run Code Online (Sandbox Code Playgroud)

self.iself.o按照您的预期自动处理.

我修改了写东西,比如:

class Foo:
    def __init__(self, in_file_name, out_file_name):
        self.i = open(in_file_name, 'r').__enter__()
        self.o = open(out_file_name, 'w').__enter__()

    def __enter__(self):
        return …
Run Code Online (Sandbox Code Playgroud)

python contextmanager

23
推荐指数
4
解决办法
937
查看次数

手动调用__enter__和__exit__

我用谷歌搜索calling __enter__ manually但没有运气.因此,让我们假设我有MySQL连接器类,它使用__enter____exit__函数(最初与with语句一起使用)来连接/断开数据库.

让我们有一个使用其中2个连接的类(例如用于数据同步).注意:这不是我现实生活中的情景,但它似乎是最简单的例子.

使这一切协同工作的最简单方法是这样的类:

class DataSync(object):

    def __init__(self):
        self.master_connection = MySQLConnection(param_set_1)
        self.slave_connection = MySQLConnection(param_set_2)

    def __enter__(self):
            self.master_connection.__enter__()
            self.slave_connection.__enter__()
            return self

    def __exit__(self, exc_type, exc, traceback):
            self.master_connection.__exit__(exc_type, exc, traceback)
            self.slave_connection.__exit__(exc_type, exc, traceback)

    # Some real operation functions

# Simple usage example
with DataSync() as sync:
    records = sync.master_connection.fetch_records()
    sync.slave_connection.push_records(records)
Run Code Online (Sandbox Code Playgroud)

:这样调用__enter__/ __exit__手动是否可以(有什么不对)吗?

Pylint 1.1.0没有对此发出任何警告,也没有找到任何关于它的文章(在开始的谷歌链接).

那叫什么呢:

try:
    # Db query
except MySQL.ServerDisconnectedException:
    self.master_connection.__exit__(None, None, None)
    self.master_connection.__enter__() …
Run Code Online (Sandbox Code Playgroud)

python contextmanager python-3.x

22
推荐指数
3
解决办法
7080
查看次数

上下文管理器和多处理池

假设您正在使用multiprocessing.Pool对象,并且您正在使用initializer构造函数的设置来传递初始化函数,然后在全局命名空间中创建资源.假设资源有一个上下文管理器.您将如何处理上下文管理资源的生命周期,前提是它必须贯穿整个过程的生命周期,但最终应该进行适当的清理?

到目前为止,我有点像这样:

resource_cm = None
resource = None


def _worker_init(args):
    global resource
    resource_cm = open_resource(args)
    resource = resource_cm.__enter__()
Run Code Online (Sandbox Code Playgroud)

从此处开始,池进程可以使用该资源.到现在为止还挺好.但处理清理有点棘手,因为multiprocessing.Pool类没有提供destructordeinitializer参数.

我的一个想法是使用该atexit模块,并在初始化程序中注册清理.像这样的东西:

def _worker_init(args):
    global resource
    resource_cm = open_resource(args)
    resource = resource_cm.__enter__()

    def _clean_up():
        resource_cm.__exit__()

    import atexit
    atexit.register(_clean_up)
Run Code Online (Sandbox Code Playgroud)

这是一个好方法吗?有更简单的方法吗?

编辑:atexit似乎没有工作.至少不是我上面使用它的方式,所以到目前为止我还没有解决这个问题的方法.

python multiprocessing contextmanager

20
推荐指数
1
解决办法
5123
查看次数

Python*与*语句完全等同于尝试 - (除外) - finally块?

我知道这已被广泛讨论,但我仍然找不到答案来证实这一点:with语句与在try - (除了)-finally块中调用相同代码相同,其中无论在__exit__函数中定义了什么上下文管理器放在finally块中?

例如 - 这两个代码片段完全相同吗?

import sys
from contextlib import contextmanager

@contextmanager
def open_input(fpath):
    fd = open(fpath) if fpath else sys.stdin
    try:
        yield fd
    finally:
        fd.close()

with open_input("/path/to/file"):
    print "starting to read from file..."
Run Code Online (Sandbox Code Playgroud)

同样如下:

def open_input(fpath):
    try:
        fd = open(fpath) if fpath else sys.stdin
        print "starting to read from file..."
    finally:
        fd.close()

open_input("/path/to/file")
Run Code Online (Sandbox Code Playgroud)

谢谢!

python with-statement contextmanager

19
推荐指数
1
解决办法
3509
查看次数

为什么MySQLdb Connection上下文管理器不关闭游标?

MySQLdb Connections有一个基本的上下文管理器,可以在enter上创建一个游标,在退出时回退或提交,并且隐式不会抑制异常.来自连接源:

def __enter__(self):
    if self.get_autocommit():
        self.query("BEGIN")
    return self.cursor()

def __exit__(self, exc, value, tb):
    if exc:
        self.rollback()
    else:
        self.commit()
Run Code Online (Sandbox Code Playgroud)

那么,有没有人知道为什么光标在退出时没有关闭?


起初,我认为这是因为关闭游标没有做任何事情,并且游标只有一个关闭方法来参考Python DB API(参见本答案的评论).但是,事实是关闭光标会烧掉剩余的结果集(如果有),并禁用光标.从光标源:

def close(self):
    """Close the cursor. No further queries will be possible."""
    if not self.connection: return
    while self.nextset(): pass
    self.connection = None
Run Code Online (Sandbox Code Playgroud)

在退出处关闭光标会很容易,所以我不得不假设它没有故意完成.另一方面,我们可以看到,当一个游标被删除时,无论如何它都会被关闭,所以我猜垃圾收集器最终会绕过它.我对Python中的垃圾收集知之甚少.

def __del__(self):
    self.close()
    self.errorhandler = None
    self._result = None
Run Code Online (Sandbox Code Playgroud)

另一个猜测是,您可能希望在with块之后重新使用光标.但我想不出你为什么需要这样做的任何理由.难道你不能总是在其上下文中使用游标,并且只为下一个事务使用单独的上下文吗?

要非常清楚,这个例子显然没有意义:

with conn as cursor:
    cursor.execute(select_stmt)

rows = …
Run Code Online (Sandbox Code Playgroud)

python mysql mysql-python contextmanager

19
推荐指数
1
解决办法
2016
查看次数

将两个上下文管理器合二为一

我使用Python 2.7,我知道我可以这样写:

with A() as a, B() as b:
    do_something()
Run Code Online (Sandbox Code Playgroud)

我想提供一个方便的助手,两者都做.此助手的用法应如下所示:

with AB() as ab:
    do_something()
Run Code Online (Sandbox Code Playgroud)

现在AB()应该做两件事:创建上下文A()并创建上下文B().

我不知道如何编写这个便利助手

python contextmanager

19
推荐指数
1
解决办法
1633
查看次数