Gardez le gestionnaire de contexte ouvert après une instruction if… else [duplicate]

Nov 23 2020

J'ai le schéma suivant, avec différentes withinstructions conditionnelles :

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

La dernière ligne échoue dans le remotecas car le sftpgestionnaire d'objets / contextes a expiré.

J'ai lu Conditionnel avec instruction en Python , mais ici ce n'est pas exactement la même chose: je pourrais créer un gestionnaire de contexte factice pour le cas non distant, mais je ne suis pas sûr que ce serait suffisant.

J'ai pensé à utiliser, ExitStackmais j'ai peur que cela semble complexe lors de l'ouverture de fichiers supplémentaires: chaque simple with _open(...) as f:devrait être réécrit dans un stack.enter_context(_open(...))code moins lisible lorsque du code supplémentaire arrive.

Quelle est la solution la plus simple dans ce cas? (en évitant de créer de nouvelles fonctions si possible et en gardant un flux if ... else simple)

Réponses

2 norok2 Nov 23 2020 at 06:59

La caractéristique principale de votre code est que vous voulez que votre with _open(): ...gestionnaire de contexte soit à l'intérieur d'un autre gestionnaire de contexte pour la branche distante et qu'il soit librement itinérant dans l'autre cas. Je pense que le plus simple est d'utiliser un gestionnaire de contexte factice, qui est discuté plus en détail ici: Comment écrire un gestionnaire de contexte nul (sans opération) en Python?

En bref, vous mettriez en place un gestionnaire de contexte factice dans le cas non distant, par exemple:

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

(ATTENTION! Je n'ai pas testé le code ci-dessus, et il utilise le monkey-patching , mais juste pour vous avoir l'idée)