2010-06-11 8 views
117

मान लीजिए कि आपके पास संदर्भ प्रबंधक के माध्यम से तीन ऑब्जेक्ट्स हैं, उदाहरण के लिए एक लॉक, एक डीबी कनेक्शन और आईपी सॉकेट। आप उनके द्वारा प्राप्त कर सकते हैं:पायथन: कई संदर्भ प्रबंधकों पर "साथ" ब्लॉक बनाएं

with lock: 
    with db_con: 
     with socket: 
      #do stuff 

लेकिन वहाँ एक ब्लॉक में यह करने के लिए एक तरीका है?

with lock,db_con,socket: 
    #do stuff 

इसके अलावा तरह कुछ, यह संभव है, वस्तुओं है कि संदर्भ प्रबंधकों की अज्ञात लंबाई की एक सरणी को देखते हुए यह संभव किसी भी तरह करना है:

a=[lock1, lock2, lock3, db_con1, socket, db_con2] 
with a as res: 
    #now all objects in array are acquired 

अगर जवाब "नहीं", ऐसा इसलिए है क्योंकि ऐसी सुविधा की आवश्यकता खराब डिजाइन का तात्पर्य है, या शायद मुझे इसे एक पेप में सुझाव देना चाहिए? :- पी

+1

[बयान 'के साथ' अजगर में एकाधिक चर] के संभावित डुप्लिकेट (http://stackoverflow.com/questions/893333/multiple-variables-in-python-with-statement): यहाँ है कि क्या इस तरह दिखाई देता –

उत्तर

212

अजगर 2.6 में और नीचे, आप contextlib.nested उपयोग कर सकते हैं:

from contextlib import nested 

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

के बराबर है:

m1, m2, m3 = A(), B(), C() 
with m1 as X: 
    with m2 as Y: 
     with m3 as Z: 
      do_something() 

ध्यान दें कि यह वास्तव में सामान्य रूप से नेस्टेड with का उपयोग कर के रूप में ही नहीं है, क्योंकि संदर्भ प्रबंधक दर्ज करने से पहले A(), B(), और C() सभी को शुरुआत में बुलाया जाएगा। यदि इनमें से कोई भी कार्य अपवाद उठा सकता है, तो यह सही तरीके से काम नहीं करेगा, लेकिन प्रश्न के उदाहरणों के लिए काम करेगा।


में अजगर 2.7 और 3.1, वाक्य रचना इस के लिए जोड़ दिया गया है, और contextlib.nested पदावनत किया गया है:

with A() as X, B() as Y, C() as Z: 
    do_something() 

में अजगर 3.3, आप भी एक अज्ञात दर्ज कर सकते हैं contextlib.ExitStack का उपयोग करके संदर्भ प्रबंधकों की लम्बाई सूची:

with ExitStack() as stack: 
    for mgr in ctx_managers: 
     stack.enter_context(mgr) 
    # ... 

यह आपको संदर्भ प्रबंधक बनाने की अनुमति देता है क्योंकि आप उन्हें ExitStack में जोड़ रहे हैं, जो contextlib.nested के साथ संभावित समस्या को रोकता है।

contextlib2 पाइथन 2 के लिए a backport of ExitStack प्रदान करता है।6 और 2.7।

+0

धन्यवाद! तो मैं इसे संदर्भ प्रबंधकों की एक सरणी के लिए 'contextlib.nested (* arr) 'के साथ उपयोग कर सकता हूं।
क्या यह किसी भी तरह से अजगर 2.7 और 3.1 के नए वाक्यविन्यास में संभव है? – olamundo

+2

@noam: नहीं, वास्तव में 3.1 में 'नेस्टेड' के लिए डॉकस्ट्रिंग कहता है: "इस कथन का एकाधिक लाभ इस तरह के कथन के एकाधिक प्रबंधक रूप पर है कि तर्क अनपॅकिंग इसे संदर्भ प्रबंधकों की एक चर संख्या के साथ उपयोग करने की अनुमति देता है निम्नानुसार है: 'नेस्टेड (* प्रबंधकों) के साथ: do_something() '" – interjay

+9

विषम, एक ओर यह बहिष्कृत है, लेकिन दूसरी तरफ वे प्रतिस्थापन पर बहिष्कृत मॉड्यूल का लाभ स्वीकार करते हैं? – olamundo

18

Python 3.1 में आपके प्रश्न का पहला भाग संभव है।

एक से अधिक आइटम के साथ

, संदर्भ प्रबंधकों कार्रवाई की जाती है के रूप में अगर बयान के साथ कई नेस्ट गया:

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

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

संस्करण 3.1 में बदल दिया है के बराबर है: समर्थन एकाधिक संदर्भ अभिव्यक्तियों के लिए

+0

धन्यवाद! लेकिन उसने अभी भी मेरे पूरे प्रश्न का उत्तर नहीं दिया: मैंने जो दूसरे मामले का उल्लेख किया है, उसके बारे में क्या है, जहां संदर्भ प्रबंधकों को सरणी में दिया गया है, यह जानने के बिना कि सरणी में कितने मैंगर्स हैं। परिणामस्वरूप कुछ python3.X '[cm1, cm2, cm3, cm4, cm5] के साथ संभव होगा: .... – olamundo

+2

@noam: अपने प्रश्न के दूसरे भाग को हल करने के लिए आप कक्षा लिख ​​सकते हैं उस वर्ग के लिए कई संसाधनों को लपेटने और '__enter__' और' __exit__' लागू करने के लिए। मुझे यकीन नहीं है कि एक मानक पुस्तकालय वर्ग है जो पहले से ही करता है। –

+0

@ मार्क मुझे नहीं लगता कि यह इतना आसान है - यही कारण है कि 'contextlib.nested() 'बहिष्कृत है। यदि अन्य चीजों की पीढ़ी और संदर्भ प्रबंधक के सक्रियण के बीच कुछ होता है, तो ऐसा हो सकता है कि क्लीनअप वांछित नहीं होता है। – glglgl

7

Python 3.3 में contextlib.ExitStack के साथ आपके प्रश्न का दूसरा भाग हल किया गया है।

1

@ इंटरजे का जवाब सही है। हालांकि, यदि आपको लंबे संदर्भ प्रबंधकों के लिए ऐसा करने की आवश्यकता है, उदाहरण के लिए mock.patch संदर्भ प्रबंधक, तो आप जल्दी से महसूस करते हैं कि आप इसे लाइनों में तोड़ना चाहते हैं। बाहर निकलता है आप उन्हें पैरों में लपेट नहीं सकते हैं, इसलिए आपको बैकस्लाश का उपयोग करना होगा।

with mock.patch('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') as a, \ 
     mock.patch('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb') as b, \ 
     mock.patch('cccccccccccccccccccccccccccccccccccccccccc') as c: 
    do_something() 
संबंधित मुद्दे