使用上下文管理器作为函数

时间:2016-10-05 22:18:15

标签: python

如果使用with语句调用,我想创建一个也可以充当上下文管理器的函数。示例用法是:

# Use as function    
set_active_language("en")

# Use as context manager
with set_active_language("en"):
    ...

这与标准函数open的使用方式非常相似。

以下是我提出的解决方案:

active_language = None  # global variable to store active language

class set_active_language(object):

    def __init__(self, language):
        global active_language
        self.previous_language = active_language
        active_language = language

    def __enter__(self):
        pass

    def __exit__(self, *args):
        global active_language
        active_language = self.previous_language

此代码不是线程安全的,但这与问题无关。

我不喜欢这个解决方案的是,类构造函数假装是一个简单的函数,仅用于它的副作用。

有更好的方法吗?

请注意,我尚未测试此解决方案。

更新:我不想将函数和上下文管理器拆分为单独的实体的原因是命名。基本上,函数和上下文管理器做同样的事情,因此为两者使用一个名称似乎是合理的。如果我想将它保持独立,则命名上下文处理器会有问题。它应该是什么? active_language?此名称可能(并将与变量名称)冲突。 override_active_language可能会有用。

2 个答案:

答案 0 :(得分:2)

技术上不,你不能这样做。但是你可以把它弄得很好,以至于人们(没有过分思考它)也不会注意到。

def set_active_language(language):
    global active_language
    previous_language = active_language
    active_language = language

    class ActiveScope(object):
        def __enter__(self):
            pass

        def __exit__(self, *args):
            global active_language
            active_language = previous_language

    return ActiveScope()

当用作函数时,ActiveScope类只是一个稍微浪费的无操作。

答案 1 :(得分:0)

希望有人会证明我错了,但我认为答案是:没有别的办法。而且,您选择的方法的另一个缺点是,当与160px语句中的其他上下文管理器一起使用时,它可能会出错。 CM的预期副作用是在对象构造上执行的,而不是在预期的with a, b, c:方法中执行。

为了能够做你想做的事,你必须从类构造函数内部知道它是在__enter__语句中初始化为上下文管理器,还是简单地作为函数调用。据我所知,没有办法收集,甚至没有with模块。