if…elseステートメントの後にコンテキストマネージャーを開いたままにします[重複]

Nov 23 2020

次のスキームがあり、条件withステートメントが異なります。

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

オブジェクト/コンテキストマネージャの有効期限が切れているremoteため、最後の行は失敗しsftpます。

PythonでConditionalwithステートメントを読みましたが、ここではまったく同じではありません。リモート以外の場合にダミーのコンテキストマネージャーを作成できますが、それで十分かどうかはわかりません。

使用することを考えましたExitStackが、さらにファイルを開くと複雑に見えるのではないかと思います。コードが到着しwith _open(...) as f:たら、単純なものを読みにくくする必要がありstack.enter_context(_open(...))ます。

この場合の最も簡単な解決策は何ですか?(可能であれば新しい関数の作成を避け、...それ以外の場合は単純に保ちます)

回答

2 norok2 Nov 23 2020 at 06:59

コードの主な機能は、with _open(): ...コンテキストマネージャーをリモートブランチの別のコンテキストマネージャー内に配置し、それ以外の場合は自由にローミングできるようにすることです。最も簡単なのは、ダミーのコンテキストマネージャーを使用することだと思います。これについては、ここで詳しく説明します。Pythonでnull(no-op)コンテキストマネージャーを作成するにはどうすればよいですか?

簡単に言うと、リモート以外の場合は、ダミーのコンテキストマネージャーを設定します。例:

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

(警告!私は上記​​のコードをテストしていません、そしてそれはモンキーパッチを使用しますが、あなたにアイデアを得るためだけです)