Использование разных контекстных менеджеров в зависимости от условий - PullRequest
0 голосов
/ 01 октября 2018

Можно ли выполнить один блок с использованием разных контекстных менеджеров в зависимости от какого-либо условия?

Пример:

if some_condition:
    with ContextManager(**args) as contex:
        ... # some block
else:
    with OtherContextManager(**other_args) as contex:
        ... # the same block

Одним из способов было бы заключить ... в функцию,но это может быть не слишком удобно в моем случае.Есть ли другая возможность?

Ответы [ 3 ]

0 голосов
/ 01 октября 2018

Как насчет ...

with ContextManager(**args) if some_condition else OtherContextManager(**other_args) as contex:
    ... # some block

...?

0 голосов
/ 01 октября 2018

Мы можем просто сойти с ума и воспользоваться тем фактом, что __enter__ и __exit__ являются просто методами и что они вызываются в исходном объекте (а не в том, который возвращается __enter__):

class WrapperContext:

 def __init__(self, condition):
     if condition:
         self.real_context = ContextA()
     else:
         self.real_context = ContextB()

 def __enter__(self):
     return self.real_context.__enter__()

 def __exit__(self):
     return self.real_context.__exit__()

и используйте его так:

 with WrapperContext(condition) as obj:
0 голосов
/ 01 октября 2018

Вы можете сохранить созданный объект в переменной, например:

if some_condition:
    cm = ContextManager(**args)
else:
    cm = OtherContextManager(**other_args)

with cm as contex:
        ... # some block

Вышесказанное может быть легко расширено до трех возможных менеджеров контекста и т. Д. Вы также можете решить, например, сначала «исправить»менеджер контекста перед «входом» в контекст.

Хотя обычно встречается такой шаблон, как with foo() as bar:, на самом деле Python просто оценивает foo(), получает этот элемент и вызывает .__enter__() для объекта,Результат этого метода сохраняется в bar.

Так что в вызове foo() нет ничего «особенного», вы можете использовать любой тип объекта с левой стороны,Таким образом, например, вы можете инкапсулировать логику if - else в отдельную функцию и вернуть менеджер контекста, а затем использовать переменную или передать менеджеры контекста в качестве параметров.Пока вы используете его в операторе with, Python будет вызывать .__enter__(..) и .__exit__(..) за занавесом.

...