Pozostaw menedżera kontekstu otwartego po instrukcji if… else [duplikat]

Nov 23 2020

Mam następujący schemat z różnymi withinstrukcjami 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, remoteponieważ sftpmenedż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, ExitStackale 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

2 norok2 Nov 23 2020 at 06:59

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ł)