संदर्भ प्रबंधक को एक ... के बाद खुला रखें

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ऑब्जेक्ट / संदर्भ प्रबंधक की समय सीमा समाप्त हो गई है।

मैंने पायथन में बयान के साथ सशर्त पढ़ा है , लेकिन यहां यह बिल्कुल समान नहीं है: मैं गैर-दूरस्थ मामले के लिए एक डमी संदर्भ प्रबंधक बना सकता हूं, लेकिन मुझे यकीन नहीं है कि यह पर्याप्त होगा।

मैंने उपयोग करने के बारे में सोचा है, ExitStackलेकिन फिर मुझे डर है कि आगे की फाइलें खोलने पर यह जटिल लगेगा: प्रत्येक सरल with _open(...) as f:को कम पठनीय में फिर से लिखना होगा stack.enter_context(_open(...))जब कुछ और कोड आ रहे हैं।

इस मामले में सबसे सरल उपाय क्या है? (यदि संभव हो तो नए कार्यों को बनाने से बचें और एक सरल रखें ... और प्रवाह)

जवाब

2 norok2 Nov 23 2020 at 06:59

आपके कोड की मुख्य विशेषता यह है कि आप चाहते हैं कि आपका with _open(): ...संदर्भ प्रबंधक दूरस्थ शाखा के लिए किसी अन्य संदर्भ प्रबंधक के अंदर हो और अन्य मामले में स्वतंत्र रूप से रोमिंग में हो। मुझे लगता है कि सबसे आसान एक डमी संदर्भ प्रबंधक का उपयोग करना है, जिसकी चर्चा यहां अधिक गहराई से की गई है: मैं पायथन में एक अशक्त (नो-ऑप) प्रसंग कैसे लिखूं?

संक्षेप में, आप गैर-दूरस्थ मामले में एक डमी संदर्भ प्रबंधक स्थापित करेंगे, जैसे:

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

(चेतावनी! मैंने उपरोक्त कोड का परीक्षण नहीं किया है, और यह बंदर-पैचिंग का उपयोग करता है , लेकिन सिर्फ आपको विचार प्राप्त करने के लिए)