2015-06-05 6 views
7

के रूप में उपयोग किया जा सकता है क्या पाइथन में एक वर्ग लिखने का कोई तरीका है जो त्रुटि के साथ उपयोग किए जाने तक त्रुटि करेगा?एक पायथन क्लास लिखना जिसे केवल संदर्भ प्रबंधक

# Okay: 
with Foo() as f1: 
    f1.func1() 
    f1.func2() 

# Not okay: 
f2 = Foo() 
f2.func1() 

मैं इसे स्वयं कर सकते हैं: __enter__ एक ध्वज सेट और कहा कि ध्वज के लिए हर दूसरे विधि की जांच किया है। लेकिन क्या ऐसा करने का एक अच्छा तरीका है?

यहाँ के लिए कोड है नहीं-तो-के बाद से जिस तरह से:

class Foo(object): 
    def __init__(self): 
     self._entered = False 

    def __enter__(self): 
     self._entered = True 
     return self 

    def _verify_entered(self): 
     if not self._entered: 
      raise Exception("Didn't get call to __enter__") 

    def __exit__(self, typ, val, traceback): 
     self._verify_entered() 
     print("In __exit__") 

    def func1(self): 
     self._verify_entered() 
     # do stuff ... 

    def func2(self): 
     self._verify_entered() 
     # do other stuff 
+0

क्या आपको त्रुटि के कारण 'foo() 'की आवश्यकता है, या' f2.func1()' ठीक होगा? – Blckknght

+0

@Blckknght, Foo() कारण होने के कारण त्रुटि केवल f2.func1() करने के लिए मामूली रूप से बेहतर होगी – kuzzooroo

+2

आप मैन्युअल रूप से चेक को स्वचालित रूप से लागू करने के लिए सजावट या मेटाक्लास का उपयोग कर सकते हैं। – agf

उत्तर

3

तकनीकी रूप से, मुझे लगता है कि एएफएफ इस अर्थ में सही है कि आप सामान को स्वचालित करने के लिए मेटाक्लास का उपयोग कर सकते हैं। हालांकि, अगर मैं इसके पीछे मौलिक प्रेरणा को सही ढंग से समझता हूं, तो मैं एक अलग तरीके से सुझाव दूंगा।

मान लें कि आपके पास Payload कक्षा है जिसे आप संदर्भ प्रबंधक के माध्यम से सुरक्षित करना चाहते हैं।

# This should go in a private module. 
class Payload(object): 
    def __init__(self): 
     print 'payload ctor' 

# This should go in the public interface. 
class Context(object): 
    def __init__(self): 
     # Set up here the parameters. 
     pass 

    def __enter__(self): 
     # Build & return a Payload object 
     return Payload() 

    def __exit__(self, exc_type, exc_val, exc_tb): 
     # Cleanup 
     pass 

with Context() as f: 
    # f here is a Payload object. 

आप एक निजी मॉड्यूल में Payload छिपाते हैं, तो आप अच्छा कर रहे हैं: इस मामले में, आप बस एक संदर्भ प्रबंधक है कि यह रिटर्न पैदा करते हैं।

2

आप अपने __enter__ विधि self तुलना में एक अलग ऑब्जेक्ट प्रदान करता है, तो आप एक उपयोगकर्ता पर तरीकों कॉल करने के लिए सक्षम होने के लिए नहीं करना चाहते हो सकता है संदर्भ प्रबंधक खुद ऑब्जेक्ट।

class Foo(object): 
    def __enter__(self): 
     print("In __enter__") 
     return Bar() 

    def __exit__(self, typ, val, traceback): 
     print("In __exit__") 

class Bar(object): 
    def func1(self): 
     print("In func1") 

    def func2(self): 
     print("In func2") 

आप निश्चित रूप से कर सकते हैं Foo और Bar कक्षाएं अधिक एक साथ की तुलना में मैं इस उदाहरण के लिए बंधे है। उदाहरण के लिए, Foo कक्षा कन्स्ट्रक्टर __enter__ में स्वयं को पास कर सकती है।

कॉलिंग Foo().func1() स्पष्ट कारण के लिए काम नहीं करेगा कि Foo में ऐसी कोई विधि नहीं है। यदि आप Bar उपयोगकर्ता को दिखाई नहीं दे रहे थे, तो आप अंडरस्कोर के साथ अपना नाम उपसर्ग कर सकते हैं (यह संकेत दे रहा है कि यह आंतरिक है) या Foo कक्षा (या यहां तक ​​कि __enter__ विधि, यदि आप वास्तव में चरम होना चाहते हैं) के भीतर भी घोंसला कर सकते हैं।

+0

:-) मुझे लगता है कि आपके जैसा सटीक उत्तर मिल गया है। –

संबंधित मुद्दे