एक 'के साथ' बयान में कई चर?


391

क्या withपायथन में एक बयान का उपयोग करके एक से अधिक चर घोषित करना संभव है ?

कुछ इस तरह:

from __future__ import with_statement

with open("out.txt","wt"), open("in.txt") as file_out, file_in:
    for line in file_in:
        file_out.write(line)

... या समस्या एक ही समय में दो संसाधनों की सफाई कर रही है?


शायद इस तरह: [expr1, expr2] के साथ f: और फिर f [0] और f [1] का उपयोग करें।
जब्बासो

अच्छा होगा क्योंकि कुछ आयात करने की आवश्यकता नहीं है .... लेकिन यह काम नहीं करता है गुण: 'सूची' ऑब्जेक्ट में कोई विशेषता नहीं है ' बाहर निकलें '
pufferfish

अगर अजगर बस बंद हो गया था, तो आपको स्टेटमेंट की आवश्यकता नहीं होगी
BT

आपको कथन के साथ उपयोग करने की आवश्यकता नहीं है , है ना? आप किसी को भी file_out और file_in सेट कर सकते हैं, फिर एक कोशिश करें / छोड़कर / अंत में जहां आप उन्हें खोलते हैं और उन्हें प्रयास में संसाधित करते हैं, और फिर अंत में उन्हें बंद कर देते हैं यदि वे कोई नहीं हैं। उसके लिए किसी दोहरे आक्षेप की आवश्यकता नहीं है।
एम काटज़

1
इनमें से कई उत्तर बयानों के साथ दो से अधिक की आवश्यकता से नहीं निपटते हैं। सैद्धांतिक रूप से ऐसे अनुप्रयोग हो सकते हैं जिन्हें दसियों संदर्भों को खोलने की आवश्यकता होती है, घोंसला बहुत जल्दी टूट जाता है किसी भी लाइन की लंबाई सीमाएं लगाई जाती हैं।
थोरसुमोनर

जवाबों:


666

यह v3.1 और पायथन 2.7 के बाद से पायथन 3 में संभव है । नया withसिंटैक्स एकाधिक संदर्भ प्रबंधकों का समर्थन करता है:

with A() as a, B() as b, C() as c:
    doSomething(a,b,c)

इसके विपरीत contextlib.nested, यह गारंटी देता है कि aऔर bउनके पास __exit__()बुलाया जाएगा भले ही C()या यह __enter__()विधि एक अपवाद उठाती हो।

आप बाद के परिभाषाओं में पहले चर का उपयोग कर सकते हैं ( नीचे एच / टी अहमद ):

with A() as a, B(a) as b, C(a, b) as c:
    doSomething(a, c)

1
क्या यह संभव है कि कुछ के बराबर फ़ील्ड्स को स्टेटमेंट में कहा जाए with open('./file') as arg.x = file:?
चार्ली पार्कर

13
इसके अलावा, यह संभव है: ए () के रूप में ए, बी (ए) के रूप में बी, सी (ए, बी) के रूप में सी:
अहमद योसोफान

वर्ग test2: x = 1; t2 = test2 () ओपन के साथ ('f2.txt') t2.x के रूप में: t1.x.readlines में l1 के लिए (): प्रिंट (l1); # चार्ली पार्कर # अजगर 3.6 में परीक्षण किया गया
अहमद योसोफैन

1
कृपया ध्यान दें, asवैकल्पिक है।
श्लोओमिर लेनर्ट

यह स्पष्ट करने के लिए कि @ SławomirLenart क्या कह रहा है: asयदि आपको ऑब्जेक्ट की आवश्यकता है aया आवश्यक है b, लेकिन पूरे as aया as bआवश्यक नहीं है
Ciprian Tomoiagă

56

contextlib.nested इसका समर्थन करता है:

import contextlib

with contextlib.nested(open("out.txt","wt"), open("in.txt")) as (file_out, file_in):

   ...

अद्यतन:
प्रलेखन उद्धृत करने के लिए, के बारे में contextlib.nested:

संस्करण 2.7 के बाद से पदावनत : कथन के साथ अब इस कार्यक्षमता का सीधे समर्थन करता है (भ्रमित करने वाली त्रुटि के बिना)।

देखें Rafał Dowgird के जवाब में अधिक जानकारी के लिए।


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

तुमने ऐसा क्यों कहा? प्रलेखन का कहना है कि नेस्टेड का उपयोग नेस्टेड के बराबर है
जेम्स हॉपकिन

@ रफाल: मैनुअल पर एक नज़र यह इंगित करती है कि अजगर बयानों के साथ ठीक से घोंसला बनाता है। वास्तविक समस्या यह है कि दूसरी फाइल बंद होने पर एक अपवाद फेंकता है।
अज्ञात

10
@ नाम: नहीं, डॉक्सहोमथॉन . org / library / contextlib.html#contextlib.nested पर डॉक्स में समतुल्य कोड मानक नेस्टेड withब्लॉकों से भिन्न होता है । प्रबंधकों को ब्लॉकों के साथ प्रवेश करने से पहले बनाया जाता है : एम 1, एम 2, एम 3 = ए (), बी (), सी () यदि बी () या सी () अपवाद के साथ विफल रहता है, तो आपकी ए को ठीक से अंतिम रूप देने की एकमात्र उम्मीद है ( ) कचरा संग्रहकर्ता है।
राफेल डोवगार्ड

8
2.7 संस्करण के बाद से पदावनत । नोट: कथन के साथ अब इस कार्यक्षमता का सीधे समर्थन करता है (भ्रामक त्रुटि प्रवण quirks के बिना)।
मीकू

36

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

with A() as a, \
     B() as b, \
     C() as c:
    doSomething(a,b,c)

कोष्ठक काम नहीं करते हैं, क्योंकि पायथन इसके बजाय एक नल बनाता है।

with (A(),
      B(),
      C()):
    doSomething(a,b,c)

चूंकि ट्यूपल्स में एक __enter__विशेषता का अभाव है , इसलिए आपको एक त्रुटि मिलती है (अवांछनीय और वर्ग प्रकार की पहचान नहीं करता है):

AttributeError: __enter__

यदि आप asकोष्ठक के भीतर उपयोग करने की कोशिश करते हैं , तो पाइथन समय पर गलती पकड़ लेता है:

with (A() as a,
      B() as b,
      C() as c):
    doSomething(a,b,c)

सिंटैक्स त्रुटी: अमान्य सिंटैक्स

https://bugs.python.org/issue12782 इस मुद्दे से संबंधित प्रतीत होता है।


16

मुझे लगता है कि आप इसके बजाय ऐसा करना चाहते हैं:

from __future__ import with_statement

with open("out.txt","wt") as file_out:
    with open("in.txt") as file_in:
        for line in file_in:
            file_out.write(line)

5
यह है कि मैं वर्तमान में यह कैसे करता हूं, लेकिन तब घोंसला दो बार जितना गहरा होता है, मैं चाहता हूं (मतलब) यह होना चाहिए ...
pufferfish

मुझे लगता है कि यह सबसे साफ तरीका है - किसी भी अन्य दृष्टिकोण को पढ़ना मुश्किल होगा। एलेक्स मार्टेली का जवाब आप जो चाहते हैं उसके करीब लगता है लेकिन बहुत कम पठनीय है। ऐसी चिंता क्यों है?
एंड्रयू हरे

7
कोई बड़ी बात नहीं है, वास्तव में, लेकिन, "प्रति आयात" (उर्फ "ज़ेन ऑफ पायथन") के अनुसार, "फ्लैट नेस्टेड से बेहतर है" - यही कारण है कि हमने मानक पुस्तकालय में संदर्भ-सूची जोड़ दी। BTW, 3.1 में एक नया सिंटैक्स हो सकता है "ए () के रूप में ए, बी () के रूप में बी:" (पैच में है, हालांकि इसके बारे में कोई BDFL उच्चारण नहीं है) अधिक प्रत्यक्ष समर्थन के लिए (इसलिए स्पष्ट रूप से पुस्तकालय समाधान isn ' टी को सही माना जाता है ... लेकिन अनचाहे घोंसले से बचने निश्चित रूप से कोर पायथन डेवलपर्स के बीच एक व्यापक रूप से साझा लक्ष्य है)।
एलेक्स मार्टेली

2
@ एलेक्स: बहुत सच है लेकिन हमें यह भी विचार करना चाहिए कि "पठनीयता मायने रखती है"।
एंड्रयू हरे

4
@ और: मुझे लगता है कि इंडेंटेशन का एक स्तर बेहतर ढंग से कार्यक्रम के इच्छित तर्क को व्यक्त करता है, जो "परमाणु" के लिए दो चर बनाते हैं, और बाद में उन्हें एक साथ साफ करते हैं (मुझे एहसास है कि वास्तव में ऐसा नहीं होता है)। विचार करें कि अपवाद मुद्दा एक सौदा ब्रेकर है
पफरफिश

12

पायथन 3.3 के बाद से, आप मॉड्यूल ExitStackसे कक्षा का उपयोग कर सकते हैं contextlib

यह संदर्भ-जागरूक वस्तुओं की एक गतिशील संख्या का प्रबंधन कर सकता है , जिसका अर्थ है कि यह विशेष रूप से उपयोगी साबित होगा यदि आप नहीं जानते कि आप कितनी फ़ाइलों को संभालने जा रहे हैं।

प्रलेखन में उल्लिखित विहित उपयोग-मामला फाइलों की एक गतिशील संख्या का प्रबंधन कर रहा है।

with ExitStack() as stack:
    files = [stack.enter_context(open(fname)) for fname in filenames]
    # All opened files will automatically be closed at the end of
    # the with statement, even if attempts to open files later
    # in the list raise an exception

यहाँ एक सामान्य उदाहरण है:

from contextlib import ExitStack

class X:
    num = 1

    def __init__(self):
        self.num = X.num
        X.num += 1

    def __repr__(self):
        cls = type(self)
        return '{cls.__name__}{self.num}'.format(cls=cls, self=self)

    def __enter__(self):
        print('enter {!r}'.format(self))
        return self.num

    def __exit__(self, exc_type, exc_value, traceback):
        print('exit {!r}'.format(self))
        return True

xs = [X() for _ in range(3)]

with ExitStack() as stack:
    print(stack._exit_callbacks)
    nums = [stack.enter_context(x) for x in xs]
    print(stack._exit_callbacks)
print(stack._exit_callbacks)
print(nums)

आउटपुट:

deque([])
enter X1
enter X2
enter X3
deque([<function ExitStack._push_cm_exit.<locals>._exit_wrapper at 0x7f5c95f86158>, <function ExitStack._push_cm_exit.<locals>._exit_wrapper at 0x7f5c95f861e0>, <function ExitStack._push_cm_exit.<locals>._exit_wrapper at 0x7f5c95f86268>])
exit X3
exit X2
exit X1
deque([])
[1, 2, 3]

0

पायथन 3.1+ में आप कई संदर्भ अभिव्यक्तियों को निर्दिष्ट कर सकते हैं, और उन्हें संसाधित किया जाएगा जैसे कि कई with कथन नेस्टेड थे:

with A() as a, B() as b:
    suite

के बराबर है

with A() as a:
    with B() as b:
        suite

इसका मतलब यह भी है कि आप दूसरे में पहली अभिव्यक्ति से उपनाम का उपयोग कर सकते हैं (डीबी कनेक्शन / कर्सर के साथ काम करते समय उपयोगी):

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