Pozostaw menedżera kontekstu otwartego po instrukcji if… else [duplikat]
Mam następujący schemat z różnymi with
instrukcjami warunkowymi :
if not remote:
_open = open
os.chdir(localpath)
else:
sftp = pysftp.Connection(host, username=user, password=sftppwd)
with sftp:
sftp.chdir(remotepath)
_open = sftp.open
with _open('myfile', 'rb') as f: # and then lots of other files are opened too
x = f.read(4)
...
Ostatnia linia kończy się niepowodzeniem, remote
ponieważ sftp
menedżer obiektów / kontekstów wygasł.
Przeczytałem warunkowe z instrukcją w Pythonie , ale tutaj nie jest dokładnie to samo: mógłbym stworzyć fałszywego menedżera kontekstu dla przypadku nie zdalnego, ale nie jestem pewien, czy to wystarczy.
Myślałem o użyciu, ExitStack
ale obawiam się, że przy otwieraniu kolejnych plików wyglądałoby to na skomplikowane: każdy prosty with _open(...) as f:
musiałby zostać przepisany na mniej czytelny, stack.enter_context(_open(...))
gdy nadejdzie więcej kodu.
Jakie jest najprostsze rozwiązanie w tym przypadku? (unikaj tworzenia nowych funkcji, jeśli to możliwe i zachowaj prosty przepływ if ... else)
Odpowiedzi
Główną cechą twojego kodu jest to, że chcesz, aby twój with _open(): ...
menedżer kontekstu znajdował się wewnątrz innego menedżera kontekstu dla zdalnego oddziału, a w drugim przypadku mógł swobodnie wędrować. Myślę, że najłatwiej jest użyć fikcyjnego menedżera kontekstu, który jest omówiony bardziej szczegółowo tutaj: Jak napisać pustego (no-op) menedżera kontekstu w Pythonie?
Krótko mówiąc, skonfigurowałbyś fikcyjnego menedżera kontekstu w przypadku nie zdalnym, na przykład:
import os
# from contextlib import suppress as nullcontext # Python 3.4+
from contextlib import nullcontext # Python 3.7+
import pysftp
remote = False
localpath = '.'
remotepath = '.'
if not remote:
_open_cm = nullcontext()
_open_cm.chdir = os.chdir
_open_cm.open = open
_path = localpath
else:
_open_cm = pysftp.Connection(host, username=user, password=sftppwd)
_path = remotepath
with _open_cm:
_open_cm.chdir(_path)
with _open_cm.open('myfile', 'rb') as f:
x = f.read(4)
...
(OSTRZEŻENIE! Nie testowałem powyższego kodu i używa on małpiego poprawiania , ale tylko po to, aby uzyskać pomysł)