2010-06-10 16 views
301

मैं पहली बार पाइथन with कथन में आया था। मैं पाइथन का प्रयोग कई महीनों से हल्के ढंग से कर रहा हूं और इसके अस्तित्व को भी नहीं जानता! इसकी कुछ हद तक अस्पष्ट स्थिति को देखते हुए, मैंने सोचा कि यह पूछ लायक हो जाएगा:पाइथन "साथ" कथन के लिए डिज़ाइन किया गया है?

  1. क्या अजगर with बयान तैयार किया गया है के लिए प्रयोग की जाने वाली है?
  2. क्या आप इसका उपयोग करते हैं?
  3. क्या कोई गॉथचास है, मुझे से जुड़े सामान्य एंटी-पैटर्न के बारे में पता होना चाहिए? with की तुलना में try..finally बेहतर उपयोग करने वाले किसी भी मामले में?
  4. इसका उपयोग अधिक व्यापक रूप से क्यों नहीं किया जाता है?
  5. कौन सा मानक लाइब्रेरी कक्षाएं इसके अनुकूल हैं?
+1

बस रिकार्ड के लिए, [यहाँ है पर द्वारा फ़ाइल को बंद करने 'साथ'] (https://docs.python.org/3/reference/compound_stmts.html#with) पायथन 3 दस्तावेज़ में। – Alexey

उत्तर

312
  1. में उपलब्ध है

    मेरा मानना ​​है कि इसका पहले से ही मेरे सामने अन्य उपयोगकर्ताओं द्वारा उत्तर दिया गया है, इसलिए मैं केवल पूर्णता के लिए इसे जोड़ता हूं: with कथन सामान्य तैयारी और सफाई कार्यों को तथाकथित context managers में अपनाने के द्वारा अपवाद हैंडलिंग को सरल बनाता है। अधिक जानकारी PEP 343 में मिल सकती है। उदाहरण के लिए, open कथन स्वयं में एक संदर्भ प्रबंधक है, जो आपको एक फ़ाइल खोलने देता है, इसे तब तक खोलें जब तक कि निष्पादन with कथन के संदर्भ में है जहां आपने इसका उपयोग किया था, और जैसे ही आप इसे छोड़ते हैं संदर्भ, इससे कोई फर्क नहीं पड़ता कि आपने अपवाद के कारण या नियमित नियंत्रण प्रवाह के दौरान इसे छोड़ा है या नहीं। इस प्रकार with कथन का उपयोग C12+ में RAII pattern के समान तरीकों से किया जा सकता है: कुछ संसाधन with कथन द्वारा अधिग्रहण किया जाता है और जब आप with संदर्भ छोड़ते हैं तो जारी किया जाता है।

  2. कुछ उदाहरण हैं:, with open(filename) as fp: का उपयोग करके खोलने फ़ाइलें with lock: का उपयोग कर (जहां lockthreading.Lock का एक उदाहरण है) ताले प्राप्त करने। आप contextlib से contextmanager सजावटी का उपयोग करके अपने स्वयं के संदर्भ प्रबंधक भी बना सकते हैं। उदाहरण के लिए, मैं अक्सर इस का उपयोग मैं वर्तमान निर्देशिका अस्थायी रूप से बदल सकते हैं और फिर मैं कहाँ था पर लौटने के लिए जब:

    from contextlib import contextmanager 
    import os 
    
    @contextmanager 
    def working_directory(path): 
        current_dir = os.getcwd() 
        os.chdir(path) 
        try: 
         yield 
        finally: 
         os.chdir(current_dir) 
    
    with working_directory("data/stuff"): 
        # do something within data/stuff 
    # here I am back again in the original working directory 
    

    यहाँ एक और उदाहरण है कि अस्थायी तौर पर कुछ अन्य फ़ाइल हैंडल करने के लिए sys.stdin, sys.stdout और sys.stderr पुनर्निर्देश और उन्हें पुनर्स्थापित करता है बाद में:

    from contextlib import contextmanager 
    import sys 
    
    @contextmanager 
    def redirected(**kwds): 
        stream_names = ["stdin", "stdout", "stderr"] 
        old_streams = {} 
        try: 
         for sname in stream_names: 
          stream = kwds.get(sname, None) 
          if stream is not None and stream != getattr(sys, sname): 
           old_streams[sname] = getattr(sys, sname) 
           setattr(sys, sname, stream) 
         yield 
        finally: 
         for sname, stream in old_streams.iteritems(): 
          setattr(sys, sname, stream) 
    
    with redirected(stdout=open("/tmp/log.txt", "w")): 
        # these print statements will go to /tmp/log.txt 
        print "Test entry 1" 
        print "Test entry 2" 
    # back to the normal stdout 
    print "Back to normal stdout again" 
    

    और अंत में, एक और उदाहरण है कि एक अस्थायी फ़ोल्डर बनाता है और यह को साफ जब संदर्भ छोड़ने:

    from tempfile import mkdtemp 
    from shutil import rmtree 
    
    @contextmanager 
    def temporary_dir(*args, **kwds): 
        name = mkdtemp(*args, **kwds) 
        try: 
         yield name 
        finally: 
         shutil.rmtree(name) 
    
    with temporary_dir() as dirname: 
        # do whatever you want 
    
+13

के लिए स्पष्ट रूप से छिपा हुआ है आरएआईआई की तुलना में जोड़ना। एक सी ++ प्रोग्रामर के रूप में जिसने मुझे सब कुछ बताया जो मुझे जानने की जरूरत थी। –

+0

ठीक है तो मुझे यह स्पष्ट करने दें। आप कह रहे हैं कि 'with' कथन को डेटा के साथ एक वैरिएबल भरने के लिए डिज़ाइन किया गया है जब तक कि इसके तहत निर्देश पूर्ण नहीं हो जाते हैं, और फिर चर को मुक्त करते हैं? – Musixauce3000

+0

क्योंकि मैंने इसे एक पीई स्क्रिप्ट खोलने के लिए इस्तेमाल किया था। 'खुले (' myScript.py ',' r ') के साथ f: pass'। मुझे दस्तावेज की टेक्स्ट सामग्री देखने के लिए वेरिएबल 'f' को कॉल करने में सक्षम होने की उम्मीद है, क्योंकि यह तब दिखाई देगा जब दस्तावेज नियमित 'ओपन' कथन के माध्यम से 'f' को असाइन किया गया था:' f = open (' myScript.py ')। पढ़ें() '। लेकिन इसके बजाय मुझे निम्न मिला: '<_io.TextIOWrapper name = 'myScript.py' mode = 'r' एन्कोडिंग = 'cp1252'>'। इसका क्या मतलब है? – Musixauce3000

3

बयान के साथ तथाकथित संदर्भ प्रबंधकों के साथ काम करता है:

http://docs.python.org/release/2.5.2/lib/typecontextmanager.html

विचार 'के साथ' ब्लॉक छोड़ने के बाद आवश्यक सफाई करके अपवाद हैंडलिंग सरल करने के लिए है। कुछ अजगर बिल्ट-इन पहले ही संदर्भ प्रबंधकों के रूप में काम करते हैं।

8

PEP 343 - The 'with' statement देखें, अंत में एक उदाहरण खंड है।

... नया बयान अजगर भाषा के लिए "के साथ" यह कोशिश/अंत में बयान के मानक का उपयोग करता है को अलग करने के लिए संभव बनाने के लिए।

73

मैं दो दिलचस्प व्याख्यान सुझाव है:

  • PEP 343
  • Effbot पायथन के समझना बयान

1. with बयान "के साथ" "के साथ" वक्तव्य ब्लो के निष्पादन को लपेटने के लिए प्रयोग किया जाता है संदर्भ प्रबंधक द्वारा परिभाषित विधियों के साथ सीके। यह सुविधाजनक पुन: उपयोग के लिए encapsulated करने के लिए आम try...except...finally उपयोग पैटर्न की अनुमति देता है।

2. आप की तरह कुछ कर सकता है:

with open("foo.txt") as foo_file: 
    data = foo_file.read() 

या

from contextlib import nested 
with nested(A(), B(), C()) as (X, Y, Z): 
    do_something() 

या (अजगर 3,1)

with open('data') as input_file, open('result', 'w') as output_file: 
    for line in input_file: 
    output_file.write(parse(line)) 

या

lock = threading.Lock() 
with lock: 
    # Critical section of code 

3। मुझे यहां कोई एंटिपेटर्न नहीं दिख रहा है।
Dive into Python का हवाला देते हुए:

try..finally अच्छा है। बेहतर है।

4. मैं इसे अन्य भाषाओं से try..catch..finally कथन का उपयोग करने के लिए प्रोग्रामर की आदत से संबंधित है लगता है।

+3

जब आप थ्रेडिंग सिंक्रनाइज़ेशन ऑब्जेक्ट्स से निपट रहे हों तो यह वास्तव में अपने आप में आता है। पायथन में अपेक्षाकृत दुर्लभ, लेकिन जब आपको उनकी आवश्यकता होती है, तो आपको वास्तव में 'साथ' की आवश्यकता होती है। – detly

+1

diveintopython.org नीचे है (स्थायी रूप से?)। Http://www.diveintopython.net/ – snuggles

+0

पर एक अच्छा जवाब का उदाहरण, खुली फ़ाइल एक प्रमुख उदाहरण है जो खोलने के दृश्यों के पीछे दिखाता है, आईओओ, फाइल ऑपरेशंस को बंद करना कस्टम संदर्भ नाम – Mayhem

3

अंक 1, 2, और 3 समुचित रूप से कवर किया जा रहा:

4: यह अपेक्षाकृत नया है, केवल python2.6 + (या python2.5 from __future__ import with_statement का उपयोग कर)

33

पायथन with कथन Resource Acquisition Is Initialization idiom का सामान्य रूप से सी ++ में उपयोग किया जाने वाला भाषा समर्थन अंतर्निहित है। इसका उद्देश्य सुरक्षित अधिग्रहण और ऑपरेटिंग सिस्टम संसाधनों को छोड़ना है।

with कथन एक दायरे/ब्लॉक के भीतर संसाधन बनाता है। आप ब्लॉक के भीतर संसाधनों का उपयोग करके अपना कोड लिखते हैं। जब ब्लॉक से बाहर निकलता है तो ब्लॉक में कोड के नतीजे के बावजूद संसाधनों को स्पष्ट रूप से रिलीज़ किया जाता है (यानी कि ब्लॉक सामान्य रूप से या अपवाद के कारण बाहर निकलता है)।

पाइथन लाइब्रेरी में कई संसाधन जो with कथन द्वारा आवश्यक प्रोटोकॉल का पालन करते हैं और इसलिए इसे आउट-ऑफ-द-बॉक्स के साथ उपयोग किया जा सकता है। हालांकि कोई भी संसाधन बना सकता है जिसका उपयोग अच्छी तरह से प्रलेखित प्रोटोकॉल को लागू करके एक कथन में किया जा सकता है: PEP 0343

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

23

एक antipattern का एक उदाहरण एक पाश अंदर with उपयोग करने के लिए जब यह पाश बाहर with के लिए और अधिक कुशल हो जाएगा हो सकता है

उदाहरण के लिए

for row in lines: 
    with open("outfile","a") as f: 
     f.write(row) 

बनाम

with open("outfile","a") as f: 
    for row in lines: 
     f.write(row) 

पहला तरीका प्रत्येक row के लिए फ़ाइल खोलना और बंद करना है जो एस की तुलना में प्रदर्शन समस्याओं का कारण बन सकता है खोलने के साथ पारिस्थितिकी रास्ता और फ़ाइल को सिर्फ एक बार बंद कर देता है।

19

फिर पूर्णता के लिए मैं with कथन के लिए अपना सबसे उपयोगी उपयोग-मामला जोड़ूंगा।

मैं बहुत सारे वैज्ञानिक कंप्यूटिंग करता हूं और कुछ गतिविधियों के लिए मुझे Decimal लाइब्रेरी मनमाने ढंग से सटीक गणना के लिए चाहिए। मेरे कोड के कुछ हिस्से में मुझे उच्च परिशुद्धता की आवश्यकता है और अधिकांश अन्य हिस्सों के लिए मुझे कम परिशुद्धता की आवश्यकता है।

मैं एक कम संख्या को मेरा डिफ़ॉल्ट परिशुद्धता सेट और फिर with का उपयोग कुछ वर्गों के लिए एक और अधिक सटीक उत्तर प्राप्त करने:

from decimal import localcontext 

with localcontext() as ctx: 
    ctx.prec = 42 # Perform a high precision calculation 
    s = calculate_something() 
s = +s # Round the final result back to the default precision 

मैं इस hypergeometric टेस्ट के साथ एक बहुत का उपयोग करें जो बड़ी संख्या के विभाजन की आवश्यकता है परिणामी रूप फैक्टोरियल। जब आप जीनोमिक स्केल गणना करते हैं तो आपको राउंड-ऑफ और ओवरफ्लो त्रुटियों से सावधान रहना होगा।

0

आउट-ऑफ-द-बॉक्स समर्थन के लिए एक और उदाहरण है, और एक एक सा पहली बार में चौंकाने वाला है जब आप में निर्मित open() बर्ताव करता है जिस तरह से करने के लिए उपयोग किया जाता है हो सकता है कि, इस तरह के रूप में लोकप्रिय डेटाबेस मॉड्यूल की connection वस्तुओं रहे हैं:

connection वस्तुओं संदर्भ प्रबंधकों रहे हैं और के रूप में ऐसी तथापि ऊपर टिप्पणी का उपयोग करते समय एक with-statement में आउट-ऑफ-द-बॉक्स इस्तेमाल किया जा सकता, कि:

जब with-block समाप्त हो गया है, या तो एक अपवाद के साथ या बिना, कनेक्शन बंद नहीं है। यदि with-block अपवाद के साथ समाप्त होता है, तो लेनदेन वापस लुढ़का जाता है, अन्यथा लेनदेन किया जाता है।

इसका मतलब यह है प्रोग्रामर के रूप में psycopg2 docs में दिखाया गया है कनेक्शन खुद को बंद करने के लिए देखभाल करने के लिए है, लेकिन एक कनेक्शन प्राप्त, और कई with-statements में इसका इस्तेमाल करने की अनुमति देता है कि,:

conn = psycopg2.connect(DSN) 

with conn: 
    with conn.cursor() as curs: 
     curs.execute(SQL1) 

with conn: 
    with conn.cursor() as curs: 
     curs.execute(SQL2) 

conn.close() 

में उपर्युक्त उदाहरण, आप ध्यान दें कि cursorpsycopg2 की वस्तुएं संदर्भ प्रबंधक भी हैं। व्यवहार पर प्रासंगिक दस्तावेज से:

एक cursorwith-block यह बंद कर दिया है बाहर निकल जाता है, अंत में इससे जुड़ी किसी भी संसाधन जारी है। लेनदेन की स्थिति प्रभावित नहीं है।

0

प्रत्येक संभावित समाधान उपरोक्त उत्तरों में सूचीबद्ध किया गया है। डेटा फ़ाइल में मौजूद है, और यह भी बंद करने के लिए

Keywords_33=[('File_2', ['with', 'as']), 
      ('Module_2', ['from', 'import']), 
      ('Constant_3', {'bool': ['False', 'True'], 
          'none': ['None']}), 
      ('Operator_4', {'boolean_operation': {'or', 'and', 'not'}, 
          'comparison': {'is'}}), 
      ('Sequnce_operation_2', ['in', 'del']), 
      ('Klass_1', ['class']), 
      ('Function_7',['lambda', 'def', 'pass', 
          'global', 'nonlocal', 
          'return', 'yield']), 
      ('Repetition_4', ['while', 'for', 'continue', 'break']), 
      ('Condition_3', ['if', 'elif', 'else']), 
      ('Debug_2', ['assert', 'raise']), 
      ('Exception_3', ['try', 'except', 'finally'])] 
0

अजगर आम तौर पर " के साथ" बयान एक फ़ाइल खोलने के लिए प्रयोग किया जाता है, इस प्रक्रिया में:

मैं आपके संदर्भ के लिए एक संपूर्ण कीवर्ड cheatsheet बनाने एक करीबी() विधि कॉल किए बिना फ़ाइल। "साथ" कथन क्लीनअप गतिविधियों को प्रदान करके अपवाद हैंडलिंग को सरल बनाता है।

साथ की सामान्य रूप:

with open(“file name”, “mode”) as file-var: 
    processing statements 

ध्यान दें: कोई जरूरत पास बुला() फ़ाइल var.close()

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

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