确定是否与州议员通话

2024-04-25 00:06:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个函数,可以直接调用,也可以通过with语句调用,它的行为应该根据调用方式的不同而有所不同,如果通过with语句调用,则返回一个上下文管理器,否则执行上下文管理器将直接执行的操作。你知道吗

例如

class Context(object):
    def __enter__(self):
        print('start')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('end')
        return False


def myfunc():
    if called_from_with:
        return Context()
    else:
        print('start')
        print('end')

当使用以下命令从调用时:

>>> with myfunc():
>>>    print('foo')

start
foo
end

直接调用时:

>>> myfunc()

start
end

有办法吗?你知道吗

编辑:我的用例是针对一个我正在编写html的工具。我把我的初始代码放在这里:https://github.com/garyvdm/htmlwrite(请注意,它目前正在进行中。)

我希望用户能够这样写:

writer = Writer(sys.stdout)

with writer(Tag('div')):
    writer('Hello world')

writer(Tag('div', c=("Hello world 2", )))

相反:(注意对.wrapped的调用)

writer = Writer(sys.stdout)

with writer.wrapped(Tag('div')):
    writer('Hello world')

writer(Tag('div', c=("Hello world 2", )))

Tags: divhello管理器worlddeftagwithcontext
2条回答

上下文管理器不限于with语句。除了在将管理器与withcm = writer(Tag('div')),然后是with cm:)一起使用之前将其分配给变量之外,还可以在^{}中使用上下文管理器,或者分别调用__enter____exit__方法。你知道吗

更好的选择是始终从函数返回上下文管理器。如果这意味着您还需要提供一个不同的函数来提供行为的非contextmanager版本,那就这样吧。你知道吗

也就是说,您可以根据参数的数量调整行为;这就是^{}所做的。在内部,您总是创建一个上下文管理器,但是如果有更多的参数,您只需立即应用上下文:

def __call__(self, tag, *args):
    # produce a context manager
    cm = WriterContext(self, tag)
    if args:
        with cm:
            for arg in args:
                self.write(arg)
    else:
        return cm

假设您要避免的是双重上下文管理器调用,即同一个上下文管理器不应双重调用,我建议您将上下文管理器修改为可重入的。你知道吗

下面是一个使用事务的简单示例:

@contextmanager()
def foo(self):
    # if object can be shared across threads,
    # make sure only one thread can enter at a time
    # alternatively, inherit from threading.Local
    with self.lock:
        if self._transaction:
            yield
        else:
            try:
                with real_transaction() as self._transaction:
                    yield
            finally:
                self._transaction = None

相关问题 更多 >