2012-07-11 13 views
11

के साथ उपयोग करता है, मैं एक संदर्भ प्रबंधक लिखने की कोशिश कर रहा हूं जो अन्य संदर्भ प्रबंधकों का उपयोग करता है, इसलिए ग्राहकों को पूरे नुस्खा को जानने की आवश्यकता नहीं है, केवल इंटरफ़ेस जो मैं प्रस्तुत कर रहा हूं। मैं इसे @contextmanager का उपयोग करके नहीं कर सकता - yield के बाद कोड को अपवाद द्वारा बाधित होने पर निष्पादित नहीं किया जाता है, इसलिए मुझे कक्षा-आधारित प्रबंधक का उपयोग करने की आवश्यकता है।पायथन में एक संदर्भ प्रबंधक लिखना जो स्वयं ही कथन

from contextlib import contextmanager 
import pprint 

d = {} 

@contextmanager 
def simple(arg, val): 
    print "enter", arg 
    d[arg] = val 
    yield 
    print "exit", arg 
    del d[arg] 

class compl(object): 
    def __init__(self, arg, val): 
     self.arg=arg 
     self.val=val 

    def __enter__(self): 
     with simple("one",1): 
      with simple("two",2): 
       print "enter complex", self.arg 
       d[self.arg] = self.val 

    def __exit__(self,*args): 
     print "exit complex", self.arg 
     del d[self.arg] 

print "before" 
print d 
print "" 

with compl("three",3): 
    print d 
    print "" 

print "after" 
print d 
print "" 

कि इस आउटपुट:

यह एक छोटा सा उदाहरण स्क्रिप्ट है

before 
{} 

enter one 
enter two 
enter complex three 
exit two 
exit one 
{'three': 3} 

exit complex three 
after 
{} 

मैं इसे उत्पादन इस हैं:

before 
{} 

enter one 
enter two 
enter complex three 
{'one': 1, 'three': 3, 'two': 2} 

exit complex three 
exit two 
exit one 
after 
{} 

वहाँ किसी भी तरह से एक वर्ग को बताने के लिए है अन्य संदर्भ प्रबंधकों के साथ खुद को लपेटने के लिए आधारित संदर्भ प्रबंधक?

+2

यह अजगर संस्करण निर्दिष्ट करने के लिए उपयोगी होगा। –

+0

सवाल क्षमा करें, लेकिन आप ऐसा क्यों करना चाहते हैं? यह मेरे लिए केवल प्राकृतिक लगता है कि कक्षा-आधारित संदर्भ प्रबंधक को अपनी निर्भरताओं को साफ करने के बाद आखिरी बार बाहर निकलना चाहिए। –

+0

लक्ष्यीकरण पायथन 2.7, क्षमा करें –

उत्तर

12
@contextmanager 
def compl(arg, val): 
   with simple("one",1): 
        with simple("two",2): 
      print "enter complex", arg 
      try: 
                d[arg] = val 
       yield 
      finally: 
          del d[arg] 
          print "exit complex", arg 
+3

क्या आप यह पूछ सकते हैं कि पूछताछ के कोड में समस्या क्या थी, इसलिए यह समझना तेज़ है कि क्या हो रहा है? :) – n611x007

+1

@naxa: प्रश्न में पिछले दो आउटपुट उदाहरण देखें। प्रश्न में कोड पहले आउटपुट का उत्पादन करता है, उत्तर में मेरा कोड दूसरा (वांछित एक) उत्पन्न करता है। संक्षेप में: सबसे घोंसला वाले संदर्भ प्रबंधक को जल्द से जल्द बाहर निकलना चाहिए। – jfs

1

आप क्या कर रहे के साथ परेशानी यह है कि आपके __enter__ कॉल में with का उपयोग कर, जब आप अपने रैपिंग संदर्भ प्रबंधक प्रवेश में, आप दोनों दर्ज करें और फिर लिपटे संदर्भ प्रबंधकों छोड़ने है। यदि आप अपना खुद का संदर्भ प्रबंधक लिखना चाहते हैं जो रैपर में प्रवेश करते समय लिपटे संदर्भ प्रबंधकों में प्रवेश करता है, तो जब आप छोड़ते हैं तो उन्हें बाहर निकाल देता है, आपको मैन्युअल रूप से लपेटा गया संदर्भ प्रबंधकों के कार्यों को आवेदक करना होगा। आपको शायद अपवाद सुरक्षा के बारे में भी चिंता करनी होगी।

2

आप लिखते हैं, "मैं @contextmanager का उपयोग करके ऐसा नहीं कर सकता - अगर आप अपवाद से बाधित होते हैं तो उपज कॉल के बाद कोड निष्पादित नहीं होता है।" यदि आपके पास कोड होना आवश्यक है तो आप इसे try/finally ब्लॉक में डाल सकते हैं।

import contextlib 

@contextlib.contextmanager 
def internal_cm(): 
    try: 
     print "Entering internal_cm" 
     yield None 
     print "Exiting cleanly from internal_cm" 
    finally: 
     print "Finally internal_cm" 

@contextlib.contextmanager 
def external_cm(): 
    with internal_cm() as c: 
     try: 
      print "In external_cm_f" 
      yield [c] 
      print "Exiting cleanly from external_cm_f" 
     finally: 
      print "Finally external_cm_f" 

if "__main__" == __name__: 
    with external_cm() as foo1: 
     print "Location A" 
    print 
    with external_cm() as foo2: 
     print "Location B" 
     raise Exception("Some exception occurs!!") 

आउटपुट:

Entering internal_cm 
In external_cm_f 
Location A 
Exiting cleanly from external_cm_f 
Finally external_cm_f 
Exiting cleanly from internal_cm 
Finally internal_cm 

Entering internal_cm 
In external_cm_f 
Location B 
Finally external_cm_f 
Finally internal_cm 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "C:\Anaconda\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 540, in runfile 
    execfile(filename, namespace) 
    File "C:\untitled0.py", line 35, in <module> 
    raise Exception("Some exception occurs!!") 
Exception: Some exception occurs!! 
संबंधित मुद्दे