2014-10-13 16 views
26

मैं किसी अपवाद की स्थिति में ऑब्जेक्ट को अंतिम रूप देने के साधन के रूप में पाइथन के with कथन का उपयोग करने से परिचित हूं। यह आमतौर पर लग रहा हैकीवर्ड के साथ "साथ" कथन का अर्थ

with file.open('myfile.txt') as f: 
    do stuff... 

जो कम हाथ के लिए

f = file.open('myfile.txt'): 
try: 
    do stuff... 
finally: 
    f.close() 

या कोई अन्य अंतिम रूप दिए जाने की दिनचर्या एक वर्ग उपस्थित हो सकता है है की तरह।

मैं हाल ही में ओपन के साथ काम कर कोड का एक टुकड़ा है कि इस प्रस्तुत भर में आया था:

with self.shader: 
    (Many OpenGL commands) 

ध्यान दें कि किसी भी as कीवर्ड के अभाव। क्या इससे संकेत मिलता है कि __enter__ और __exit__ कक्षा के तरीकों को अभी भी बुलाया जा सकता है, लेकिन ऑब्जेक्ट का स्पष्ट रूप से ब्लॉक में उपयोग नहीं किया जाता है (यानी, यह ग्लोबल्स या अंतर्निहित संदर्भों के माध्यम से काम करता है)? या क्या कोई और अर्थ है जो मुझे दूर कर रहा है?

+2

यदि आपको 'साथ' ब्लॉक के अंदर संदर्भ प्रबंधक को उपनाम करने की आवश्यकता नहीं है, तो यह ठीक है - उदाहरण भी देखें [ 'Contextlib.suppress'] (https://docs.python.org/3.4/library/contextlib.html#contextlib.suppress)। कड़ाई से, आप खुले (...): ... 'के साथ कर सकते हैं, हालांकि, जब आप फ़ाइल हैंडलर तक नहीं पहुंच सकते हैं तो बहुत कुछ नहीं है! – jonrsharpe

उत्तर

30

संदर्भ प्रबंधक वैकल्पिक रूप सेas नामक पहचानकर्ता को असाइन करने के लिए एक ऑब्जेक्ट लौटा सकता है। और यह __enter__ विधि द्वारा लौटाई गई वस्तु है जिसे as द्वारा असाइन किया गया है, जरूरी नहीं कि संदर्भ प्रबंधक स्वयं ही हो।

as <identifier> का उपयोग करने में मदद करता है जब आप एक नई वस्तु बनाने, open() कॉल की तरह करता है, लेकिन सभी संदर्भ प्रबंधकों सिर्फ संदर्भ के लिए बनाई गई हैं। वे पुन: प्रयोज्य हो सकते हैं और उदाहरण के लिए पहले से ही बनाए जा चुके हैं।

डेटाबेस कनेक्शन लें। आप केवल एक बार डेटाबेस कनेक्शन बनाते हैं, लेकिन कई डेटाबेस एडेप्टर आपको संदर्भ प्रबंधक के रूप में कनेक्शन का उपयोग करने देते हैं; संदर्भ दर्ज करें और लेन-देन शुरू कर दिया है, यह से बाहर निकलें और लेन-देन (सफलता पर) या तो प्रतिबद्ध है, या वापस लुढ़का (जब वहाँ एक अपवाद है):

with db_connection: 
    # do something to the database 

कोई नई वस्तुओं यहाँ, बनाया जा करने की जरूरत है संदर्भ db_connection.__enter__() के साथ दर्ज किया गया है और db_connection.__exit__() के साथ फिर से बाहर निकला है, लेकिन हम पहले से ही कनेक्शन ऑब्जेक्ट का संदर्भ रखते हैं।

अब, यह हो सकता है कि कनेक्शन ऑब्जेक्ट दर्ज करते समय कर्सर ऑब्जेक्ट उत्पन्न करता है। अब यह समझ में आता है एक स्थानीय नाम पर है कि कर्सर वस्तु आवंटित करने के लिए:

with db_connection as cursor: 
    # use cursor to make changes to the database 

db_connection अभी भी यहाँ बुलाया गया था नहीं, यह पहले से ही से पहले मौजूद है, और हम पहले से ही यह करने के लिए एक संदर्भ है। लेकिन जो भी db_connection.__enter__() उत्पादित किया गया है अब cursor को सौंपा गया है और इसका उपयोग वहां से किया जा सकता है।

यह फाइल ऑब्जेक्ट्स के साथ होता है; open() एक फ़ाइल वस्तु देता है, और fileobject.__enter__() फ़ाइल वस्तु ही देता है, ताकि आप एक with बयान में open() कॉल उपयोग कर सकते हैं और एक कदम में नव निर्मित वस्तु के लिए एक संदर्भ असाइन करते हैं, बल्कि दो से।उस छोटी सी चाल के बिना, आपको इसका उपयोग करना होगा:

f = open('myfile.txt') 
with f: 
    # use `f` in the block 

यह सब आपके शेडर उदाहरण पर लागू करना; आपके पास पहले से ही self.shader का संदर्भ है। यह काफी संभावना है कि self.shader.__enter__() फिर से self.shader का संदर्भ देता है, लेकिन चूंकि आपके पास पहले से ही एक पूरी तरह से सेवा योग्य संदर्भ है, तो इसके लिए एक नया स्थानीय क्यों बनाएं?

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