अजगर "बयान" के लिए किसके साथ बनाया गया है?


418

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

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

5
सिर्फ रिकॉर्ड के लिए, यहांwith पायथन 3 प्रलेखन में है।
एलेक्सी

एक जावा बैकग्राउंड से आने के कारण, यह मुझे जावा में संबंधित " संसाधनों के साथ प्रयास" के रूप में याद रखने में मदद करता है , भले ही वह पूरी तरह से सही न हो।
vefthym

जवाबों:


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

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

    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
    

20
RAII से तुलना जोड़ने के लिए धन्यवाद। एक C ++ प्रोग्रामर के रूप में जिसने मुझे वह सब कुछ बताया जो मुझे जानना आवश्यक था।
फ्रेड थॉमसन

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

क्योंकि मैंने इसका इस्तेमाल एक पटकथा को खोलने के लिए किया था। with open('myScript.py', 'r') as f: pass। मैं चर कॉल करने के लिए सक्षम होने के लिए उम्मीद f, दस्तावेज़ के पाठ सामग्री को देखने के रूप में इस करता है, तो दस्तावेज़ को सौंपा गया क्या प्रकट होता है fएक नियमित रूप से के माध्यम से openबयान: f = open('myScript.py').read()। लेकिन इसके बजाय मुझे निम्नलिखित मिला <_io.TextIOWrapper name='myScript.py' mode='r' encoding='cp1252'>:। इसका क्या मतलब है?
मूसीकास ३०००

3
@ Musixauce3000 - वास्तविक फ़ाइल withकी आवश्यकता को दूर नहीं करता है readwithकॉल open- यह आप इसके साथ क्या करने की जरूरत नहीं जानता है - आप एक उदाहरण के लिए तलाश करने के लिए चाहते हो सकता है।
टोनी सफ़ोकल 66

@ Musixauce3000 withकथन डेटा के साथ एक चर को भर सकता है या पर्यावरण के लिए कुछ अन्य परिवर्तन कर सकता है जब तक कि इसके तहत निर्देश पूरे नहीं होते हैं, और फिर किसी भी तरह के सफाई की आवश्यकता होती है। क्लीनअप के प्रकार जो एक खुली फाइल को बंद करने जैसी चीजें हैं, या जैसा कि @Tamas ने इस उदाहरण में दिया है, निर्देशिकाओं को वापस उस स्थान पर लाना जहाँ आप पहले थे, आदि। चूंकि पायथन में कचरा संग्रह है, इसलिए एक चर को मुक्त करना महत्वपूर्ण नहीं है। उदाहरण। withआमतौर पर अन्य प्रकार के सफाई के लिए उपयोग किया जाता है।
बॉब स्टिंक

89

मैं दो दिलचस्प व्याख्यान देना चाहूंगा:

  • पीईपी 343 "स्टेटमेंट" के साथ
  • इप्टबॉन अंडरस्टैंडिंग पायथन के "स्टेटमेंट" के साथ

1.with बयान एक संदर्भ प्रबंधक द्वारा निर्धारित तरीकों के साथ एक ब्लॉक के निष्पादन रैप करने के लिए प्रयोग किया जाता है। यह सामान्य 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. मुझे यहां कोई एंटीपार्टर्न नहीं दिखता है।
का हवाला देते हुए अजगर में डुबकी :

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

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


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

1
diveintopython.org नीचे है (स्थायी रूप से?)। पर नजर आता diveintopython.net
snuggles

एक अच्छे उत्तर का उदाहरण, ओपन फाइल एक प्रमुख उदाहरण है जो खोलने के दृश्यों के पीछे दिखाता है, io, फ़ाइल संचालन को कस्टम संदर्भ नाम के साथ साफ़ तरीके से छिपाया जाता है
गुस्सा 84

40

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

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

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

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


27

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

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


26

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


10

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

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


5

अंक 1, 2, और 3 यथोचित रूप से कवर किए जा रहे हैं:

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


4

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

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

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


3

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

connectionवस्तुओं संदर्भ प्रबंधक हैं और इस तरह से बाहर के बॉक्स इस्तेमाल किया जा सकता एक में with-statementहालांकि ऊपर ध्यान दें कि का उपयोग करते समय,:

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

इसका मतलब यह है कि प्रोग्रामर को स्वयं कनेक्शन बंद करने का ध्यान रखना होगा, लेकिन कनेक्शन प्राप्त करने की अनुमति देता है, और इसका उपयोग कई में करता है with-statements, जैसा कि psycopg2 डॉक्स में दिखाया गया है :

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()

ऊपर दिए गए उदाहरण में, आप ध्यान देंगे कि cursorऑब्जेक्ट psycopg2भी संदर्भ प्रबंधक हैं। व्यवहार पर प्रासंगिक प्रलेखन से:

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


3

अजगर में आम तौर पर "के साथ " बयान का उपयोग किसी फ़ाइल को खोलने के लिए किया जाता है, फ़ाइल में मौजूद डेटा को संसाधित करता है, और एक करीबी () विधि को कॉल किए बिना फ़ाइल को बंद करने के लिए भी। "के साथ" बयान सफाई गतिविधियों प्रदान करके अपवाद से निपटने को सरल बनाता है।

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

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

नोट: फ़ाइल- var.close () पर बंद () कॉल करके फ़ाइल को बंद करने की कोई आवश्यकता नहीं है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.