Lassen Sie den Kontextmanager nach einer if… else-Anweisung [duplizieren] geöffnet.

Nov 23 2020

Ich habe das folgende Schema mit verschiedenen bedingten withAnweisungen:

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

Die letzte Zeile schlägt in diesem remoteFall fehl , weil der sftpObjekt- / Kontextmanager abgelaufen ist.

Ich habe Conditional with-Anweisung in Python gelesen , aber hier ist es nicht genau dasselbe: Ich könnte einen Dummy-Kontextmanager für den nicht entfernten Fall erstellen, bin mir aber nicht sicher, ob dies ausreichen würde.

Ich habe überlegt, es zu verwenden, ExitStackaber dann befürchte ich, dass es beim Öffnen weiterer Dateien komplex aussehen würde: Jede einfache Datei with _open(...) as f:müsste in eine weniger lesbare Datei umgeschrieben werden, stack.enter_context(_open(...))wenn mehr Code eintrifft.

Was ist in diesem Fall die einfachste Lösung? (Vermeiden Sie nach Möglichkeit das Erstellen neuer Funktionen und halten Sie einen einfachen if ... else-Fluss aufrecht.)

Antworten

2 norok2 Nov 23 2020 at 06:59

Das Hauptmerkmal Ihres Codes ist, dass Sie möchten, dass sich Ihr with _open(): ...Kontextmanager in einem anderen Kontextmanager für den Remote- Zweig befindet und im anderen Fall frei Roaming ist. Ich denke, am einfachsten ist es, einen Dummy-Kontextmanager zu verwenden, auf den hier näher eingegangen wird: Wie schreibe ich einen Null-Kontextmanager (no-op) in Python?

Kurz gesagt, Sie würden im nicht entfernten Fall einen Dummy-Kontextmanager einrichten, z.

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

(WARNUNG! Ich habe den obigen Code nicht getestet und er verwendet Affen-Patches , aber nur, um Ihnen die Idee zu vermitteln.)