Диспетчер контекста как декоратор с доступом к данному объекту - PullRequest
0 голосов
/ 24 февраля 2020

У меня есть менеджер контекста для объекта, который можно использовать аналогично диспетчеру контекста open, например,

with MyContextManager as cm:
    cm.do_something()

Я знаю, что простой менеджер контекста можно превратить в декоратор при использовании contextlib.ContextDecorator, чтобы создать его. Возможно ли также получить доступ к объекту, полученному из диспетчера контекста, если вы используете декоратор? Например, учитывая менеджер контекста выше, что-то вроде:

@cmdecorator
def my_function(self, cm):
    cm.do_something

Я не мог заставить это работать. Либо я упускаю что-то тривиальное (надеюсь, что так), либо это просто невозможно ... Это только синтактический c сахар в конце, но мне интересно, возможно ли это.

Ответы [ 2 ]

1 голос
/ 24 февраля 2020

Нет. Это явно упоминается в документации .

. Обратите внимание, что при использовании менеджеров контекста в качестве декораторов функций есть одно дополнительное ограничение: нет способа получить доступ к возвращаемому значению __enter__() , Если это значение необходимо, то все равно необходимо использовать явный оператор with.

0 голосов
/ 25 февраля 2020

Чтобы ответить на мой собственный вопрос: хотя для этого нет автоматического механизма c, достаточно просто написать декоратор, который делает именно это (используя аргумент с жестко заданным ключевым словом):

def patch_cm(f):
    @functools.wraps(f)
    def decorated(*args, **kwds):
        with MyContextManager() as cm:
            kwds['cm'] = cm
            return f(*args, **kwds)

    return decorated

который можно использовать (здесь в unittest):

class MyContextManagerTest(TestCase):
    @patch_cm
    def test_context_decorator(self, cm):
        cm.do_something()
        self.assertTrue(cm.done()) 

, что совпадает с:

def test_context_decorator(self):
    with MyContextManager() as cm:
       cm.do_something()
       self.assertTrue(cm.done()) 

(что я на самом деле использую, это обертка с аргументами, но это просто еще одна обертка вокруг ...)

...