متغيرات متعددة في بيان "مع"؟
-
23-08-2019 - |
سؤال
هل من الممكن إعلان أكثر من متغير باستخدام 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)
... أو تقوم بتنظيف اثنين من الموارد في نفس الوقت المشكلة؟
المحلول
من الممكن بيثون 3 منذ v3.1 و بيثون 2.7.. وبعد الجديد with
بناء الجملة يدعم مديري السياق المتعدد:
with A() as a, B() as b, C() as c:
doSomething(a,b,c)
على عكس. contextlib.nested
, هذا يضمن ذلك a
و b
سيكون لها __exit__()
يسمى حتى لو C()
أو هو __enter__()
الطريقة ترفع استثناء.
نصائح أخرى
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 للمزيد من المعلومات.
لاحظ أنه إذا قمت بتقسيم المتغيرات إلى خطوط، فيجب عليك استخدام Backslashes لفرض خطوط Newlines.
with A() as a, \
B() as b, \
C() as c:
doSomething(a,b,c)
الأقواس لا تعمل، لأن بيثون يخلق tuple بدلا من ذلك.
with (A(),
B(),
C()):
doSomething(a,b,c)
منذ tuples تفتقر إلى __enter__
سمة، يمكنك الحصول على خطأ (غير محدد ولا يحدد نوع الفصل):
AttributeError: __enter__
إذا حاولت استخدام as
داخل الأقواس، يلفت بيثون الخطأ في تحليل الوقت:
with (A() as a,
B() as b,
C() as c):
doSomething(a,b,c)
خطأ قواعدي: بناء جملة غير صالح
https:/bugs.python.org/issue12782. يبدو أن مرتبط بهذه المشكلة.
أعتقد أنك تريد القيام بذلك بدلا من ذلك:
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)
منذ بيثون 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]