إنشاء كتلة "مع" على العديد من مديري السياق؟ [مكرر
-
26-09-2019 - |
سؤال
هذا السؤال لديه بالفعل إجابة هنا:
- متغيرات متعددة في بيان "مع"؟ 6 إجابات
لنفترض أن لديك ثلاثة كائنات تحصل عليها عبر Manager Context ، على سبيل المثال قفل واتصال DB ومقبس IP. يمكنك الحصول عليها بواسطة:
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
إذا كانت الإجابة "لا" ، فهل لأن الحاجة إلى مثل هذه الميزة تعني تصميمًا سيئًا ، أو ربما ينبغي أن أقترحها في PEP؟ : p
المحلول
في بيثون 2.7 و 3.1 وما فوق, ، يمكنك كتابة:
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 يوفر خلفية ExitStack
لبيثون 2.6 و 2.7.
في بيثون 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()
سيتم استدعاء جميعها في البداية ، قبل الدخول إلى مديري السياق. هذا لن يعمل بشكل صحيح إذا كانت إحدى هذه الوظائف تثير استثناء.
contextlib.nested
يتم إهماله في إصدارات Python الأحدث لصالح الأساليب المذكورة أعلاه.
نصائح أخرى
الجزء الأول من سؤالك ممكن في بيثون 3.1.
مع أكثر من عنصر واحد ، تتم معالجة مديري السياق كما لو كان هناك متعددة مع عبارات متداخلة:
with A() as a, B() as b: suite
يعادل
with A() as a: with B() as b: suite
تغير في الإصدار 3.1: دعم تعبيرات السياق المتعددة
@إجابة Interjay صحيحة. ومع ذلك ، إذا كنت بحاجة إلى القيام بذلك لمديري السياق الطويل ، على سبيل المثال مديري السياق Mock.Patch ، فأنت تدرك بسرعة أنك تريد كسر هذا عبر الأسطر. اتضح أنه لا يمكنك لفهم في Parens ، لذلك عليك استخدام عمليات الرفع الخلفي. هذا ما يبدو عليه:
with mock.patch('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') as a, \
mock.patch('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb') as b, \
mock.patch('cccccccccccccccccccccccccccccccccccccccccc') as c:
do_something()
يتم حل الجزء الثاني من سؤالك contextlib.ExitStack
في بيثون 3.3.
متابعة من استجابة @sage88 ، يمكنك دائمًا تعيين هذه التصحيحات للحصول على أسماء متغيرة ذات معنى قبل الدخول إليها.
يمكنك إنشاء تلك التصحيحات في خطوط متعددة
a_patch = mock.patch('aaaaaaa')
b_patch = mock.patch('bbbbbbb')
c_patch = mock.patch('ccccccc')
with a_patch as a, b_patch as b, as c:
do_something()