python - पाइथन "के साथ" कथन क्या है?




language-features with-statement (8)

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

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

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

  2. कुछ उदाहरण हैं: with open(filename) as fp: उपयोग with open(filename) as fp: फाइलें with open(filename) as fp: with lock: ताले का उपयोग with lock: (जहां lock threading.Lock उदाहरण है। 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
    

अंक 1, 2, और 3 उचित रूप से अच्छी तरह से कवर किया जा रहा है:

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


एक एंटीपेटर्न का एक उदाहरण लूप के अंदर के with उपयोग करना हो सकता है जब लूप 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 लिए फ़ाइल खोलना और बंद करना है जो खोलने के साथ दूसरी बार की तुलना में प्रदर्शन समस्याओं का कारण बन सकता है और फ़ाइल को एक बार बंद कर देता है।


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

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

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


पूर्णता के लिए मैं कथन के 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

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


प्रत्येक संभावित समाधान उपरोक्त उत्तरों में सूचीबद्ध किया गया है।

मैं आपके संदर्भ के लिए एक विस्तृत कीवर्ड चीटशीट बना देता हूं:

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'])]

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

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

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

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


पीईपी 343 देखें - 'साथ' कथन , अंत में एक उदाहरण खंड है।

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





with-statement