29

में कथन के साथ सशर्त क्या कोई कथन के साथ कोड के ब्लॉक को शुरू करने का कोई तरीका है, लेकिन सशर्त रूप से?पायथन

कुछ की तरह:

if needs_with(): 
    with get_stuff() as gs: 

# do nearly the same large block of stuff, 
# involving gs or not, depending on needs_with() 

स्पष्ट करने के लिए, एक परिदृश्य, यानी एक ब्लॉक बयान के साथ में रखा है, जबकि एक अन्य संभावना एक ही ब्लॉक होगा, लेकिन encased नहीं (जैसे कि वह नहीं था दांतेदार)

निश्चित रूप से प्रारंभिक प्रयोगों खरोज त्रुटियों दे ..

+2

साथ के शरीर के लिए एक समारोह लिखने? –

उत्तर

28

आप कोड डुप्लिकेट करने से बचना चाहते हैं और 3.3 से पहले अजगर का एक संस्करण का उपयोग कर रहे हैं (जहां contextlib.ExitStack उपलब्ध नहीं है), तो आप

class dummy_context_mgr(): 
    def __enter__(self): 
     return None 
    def __exit__(self, exc_type, exc_value, traceback): 
     return False 

या:

import contextlib 

@contextlib.contextmanager 
def dummy_context_mgr(): 
    yield None 

और उसके बाद के रूप में उपयोग:

की तरह कुछ कर सकता है
with get_stuff() if needs_with() else dummy_context_mgr() as gs: 
    # do stuff involving gs or not 

वैकल्पिक रूप से get_stuff()needs_with() पर आधारित विभिन्न चीज़ों को वापस कर सकता है।

+3

पर' ExitStack' को बैकपोर्ट किया है यह संदर्भ प्रबंधक मानक पायथन पुस्तकालय, imho में होना चाहिए। इसके लिए धन्यवाद। – jjmontes

+0

नामों का उपयोग करने के बारे में * चाहिए _... * और * नहीं *। फिर इस तरह के बयान 'get_stuff() के साथ पढ़ेगा यदि if_get_stuff() और नहीं() gs: '? –

+0

@RiazRizvi मैं व्यक्तिगत रूप से इसे इस तरह नामित नहीं करता था; मैं सवाल से नाम का उपयोग कर रहा था। – jamesdlin

3

आप contextlib.nested उपयोग कर सकते हैं एक भी with बयान में 0 या अधिक संदर्भ प्रबंधकों डाल करने के लिए।

>>> import contextlib 
>>> managers = [] 
>>> test_me = True 
>>> if test_me: 
...  managers.append(open('x.txt','w')) 
... 
>>> with contextlib.nested(*managers):              
... pass              
...                
>>> # see if it closed 
... managers[0].write('hello')                                
Traceback (most recent call last):        
    File "<stdin>", line 2, in <module>         
ValueError: I/O operation on closed file 

इस समाधान में इसकी क्विर्क है और मैंने अभी देखा है कि 2.7 के रूप में इसे हटा दिया गया है। मैंने कई संदर्भ प्रबंधकों को जॉगलिंग को संभालने के लिए अपना खुद का संदर्भ प्रबंधक लिखा था। इसका मेरे लिए अब तक काम किया, लेकिन मैं वास्तव में नहीं पर विचार किया है बढ़त शर्तों को

class ContextGroup(object): 
    """A group of context managers that all exit when the group exits.""" 

    def __init__(self): 
     """Create a context group""" 
     self._exits = [] 

    def add(self, ctx_obj, name=None): 
     """Open a context manager on ctx_obj and add to this group. If 
     name, the context manager will be available as self.name. name 
     will still reference the context object after this context 
     closes. 
     """ 
     if name and hasattr(self, name): 
      raise AttributeError("ContextGroup already has context %s" % name) 
     self._exits.append(ctx_obj.__exit__) 
     var = ctx_obj.__enter__() 
     if name: 
      self.__dict__[name] = var 

    def exit_early(self, name): 
     """Call __exit__ on named context manager and remove from group""" 
     ctx_obj = getattr(self, name) 
     delattr(self, name) 
     del self._exits[self._exits.index(ctx_obj)] 
     ctx_obj.__exit__(None, None, None) 

    def __enter__(self): 
     return self 

    def __exit__(self, _type, value, tb): 
     inner_exeptions = [] 
     for _exit in self._exits: 
      try: 
       _exit(_type, value, tb) 
      except Exception, e: 
       inner_exceptions.append(e) 
     if inner_exceptions: 
      r = RuntimeError("Errors while exiting context: %s" 
       % (','.join(str(e)) for e in inner_exceptions)) 

    def __setattr__(self, name, val): 
     if hasattr(val, '__exit__'): 
      self.add(val, name) 
     else: 
      self.__dict__[name] = val 
+1

जैसा कि मैंने अपने उत्तर में उल्लेख किया है, पायथन 3.3 ने 'contextlib.ExitStack' जोड़ा है, जो आपके' ContextGroup' के बहुत कुछ करता है। मैं कहूंगा कि मैं थोड़ा आश्चर्यचकित हूं कि इसे वापस नहीं किया गया है, लेकिन यदि आप पाइथन> = 3.3 की आवश्यकता के लिए तैयार हैं, तो यह आपके लिए एक अच्छा मजबूत विकल्प हो सकता है। – Mike

+0

'contextlib2' एक pypi पैकेज है जिसने पायथन 2 –

25

पायथन 3.3 ने इस तरह की स्थिति के लिए contextlib.ExitStack पेश किया। यह आपको एक "ढेर" देता है, जिसके लिए आप संदर्भ प्रबंधक को आवश्यकतानुसार जोड़ते हैं। आपके मामले में, यदि आप ऐसा करते हैं: कि stack को दर्ज किया गया है

from contextlib import ExitStack 

with ExitStack() as stack: 
    if needs_with(): 
     gs = stack.enter_context(get_stuff()) 

    # do nearly the same large block of stuff, 
    # involving gs or not, depending on needs_with() 

कुछ भी हमेशा की तरह with बयान के अंत में exit एड स्वचालित रूप से है। (यदि कुछ भी दर्ज नहीं किया गया है, तो यह कोई समस्या नहीं है।) इस उदाहरण में, जो भी get_stuff() द्वारा लौटाया गया है exit एड स्वचालित रूप से है।

यदि आपको पाइथन के पहले संस्करण का उपयोग करना है, तो आप contextlib2 मॉड्यूल का उपयोग करने में सक्षम हो सकते हैं, हालांकि यह मानक नहीं है। यह इस और अन्य सुविधाओं को पायथन के पुराने संस्करणों में बैकपोर्ट करता है। यदि आप इस दृष्टिकोण को पसंद करते हैं तो आप एक सशर्त आयात भी कर सकते हैं।

+0

+1, यह चयनित उत्तर होना चाहिए। जैसा कि [यहां] बताया गया है (https://docs.python.org/3/library/contextlib.html?highlight=contextmanager#simplifying-support-for-single-optional-context-managers) यह इस तरह से निपटने के लिए है समस्या का इसके अलावा, इसे निफ्टी वन-लाइनर के रूप में भी इस्तेमाल किया जा सकता है: 'get_stuff() के साथ if_with() और exitStack() gs' के रूप में। – farsil

+0

@ एंथनीस्टाइल मैंने सोचा कि मैंने यही कहा है। – Mike

+0

डरप, मैं पूरी तरह से याद किया!/मुझे –

5

एक तृतीय-पक्ष विकल्प प्राप्त करने के लिए वास्तव में इस:
https://pypi.python.org/pypi/conditional

from conditional import conditional 

with conditional(needs_with(), get_stuff()): 
    # do stuff 
+0

हटा देता है क्या यह 'के साथ' कथन के अंत में 'जैसा ...' खंड का समर्थन करता है? –

+1

स्रोत को देख रहे हैं ... हाँ यह करता है। 'सशर्त (need_with(), get_stuff()) के साथ सामान के रूप में:' आपको 'get_stuff()' संदर्भ प्रबंधक का संदर्भ देगा (अगर और केवल अगर स्थिति पूरी हो जाती है, अन्यथा आपको 'कोई नहीं' मिलता है) – Anentropic