Múltiplas variáveis ??em um 'com' declaração?
-
23-08-2019 - |
Pergunta
É possível declarar mais de uma variável usando uma declaração with
em Python?
Algo como:
from __future__ import with_statement
with open("out.txt","wt"), open("in.txt") as file_out, file_in:
for line in file_in:
file_out.write(line)
... ou está limpando dois recursos ao mesmo tempo o problema?
Solução
É possível em Python 3 desde a v3.1 e < a href = "http://docs.python.org/dev/whatsnew/2.7.html#other-language-changes" rel = "noreferrer"> 2.7 Python . Os novos with
sintaxe suporta vários gestores de contexto:
with A() as a, B() as b, C() as c:
doSomething(a,b,c)
Ao contrário do contextlib.nested
, este garante que a
e b
terá de chamada, mesmo se __exit__()
ou do método C()
levanta uma exceção a sua __enter__()
.
Outras dicas
contextlib.nested
suporta o seguinte:
import contextlib
with contextlib.nested(open("out.txt","wt"), open("in.txt")) as (file_out, file_in):
...
Update:
Para citar a documentação, em relação contextlib.nested
:
deObsoleto desde a versão 2.7 : A-declaração com agora suporta este funcionalidade diretamente (sem erro confusas peculiaridades propensas).
Veja Rafal Dowgird resposta para obter mais informações.
Note que se você dividir as variáveis ??em linhas, você deve usar barras invertidas para embrulhar as novas linhas.
with A() as a, \
B() as b, \
C() as c:
doSomething(a,b,c)
Parênteses não fazer o trabalho, já que Python cria uma tupla vez.
with (A(),
B(),
C()):
doSomething(a,b,c)
Desde tuplas não têm um atributo __enter__
, você recebe um erro (undescriptive e não identifica o tipo de classe):
AttributeError: __enter__
Se você tentar as
uso dentro de parênteses, Python pega o erro no momento da análise:
with (A() as a,
B() as b,
C() as c):
doSomething(a,b,c)
SyntaxError: inválido sintaxe
https://bugs.python.org/issue12782 parece estar relacionada a esta questão.
Eu acho que você quer fazer isso em vez disso:
from __future__ import with_statement
with open("out.txt","wt") as file_out:
with open("in.txt") as file_in:
for line in file_in:
file_out.write(line)
Desde Python 3.3, você pode usar a classe ExitStack
do contextlib
módulo.
Ele pode gerenciar um dinâmico número de objetos sensíveis ao contexto, o que significa que ele irá revelar-se especialmente útil se você não sabe quantos arquivos você está indo para alça.
O caso de uso canônico que é mencionado na documentação está a gerir um número dinâmico de arquivos.
with ExitStack() as stack:
files = [stack.enter_context(open(fname)) for fname in filenames]
# All opened files will automatically be closed at the end of
# the with statement, even if attempts to open files later
# in the list raise an exception
Aqui está um exemplo genérico:
from contextlib import ExitStack
class X:
num = 1
def __init__(self):
self.num = X.num
X.num += 1
def __repr__(self):
cls = type(self)
return '{cls.__name__}{self.num}'.format(cls=cls, self=self)
def __enter__(self):
print('enter {!r}'.format(self))
return self.num
def __exit__(self, exc_type, exc_value, traceback):
print('exit {!r}'.format(self))
return True
xs = [X() for _ in range(3)]
with ExitStack() as stack:
print(stack._exit_callbacks)
nums = [stack.enter_context(x) for x in xs]
print(stack._exit_callbacks)
print(stack._exit_callbacks)
print(nums)
Output:
deque([])
enter X1
enter X2
enter X3
deque([<function ExitStack._push_cm_exit.<locals>._exit_wrapper at 0x7f5c95f86158>, <function ExitStack._push_cm_exit.<locals>._exit_wrapper at 0x7f5c95f861e0>, <function ExitStack._push_cm_exit.<locals>._exit_wrapper at 0x7f5c95f86268>])
exit X3
exit X2
exit X1
deque([])
[1, 2, 3]