هل يمكنني استخدام بيثون مع بيان للتنفيذ الشرطي؟

StackOverflow https://stackoverflow.com/questions/4314338

  •  29-09-2019
  •  | 
  •  

سؤال

أحاول كتابة رمز يدعم الدلالات التالية:

with scope('action_name') as s:
  do_something()
  ...
do_some_other_stuff()

يجب أن يقرر النطاق ، من بين أشياء أخرى (الإعداد ، التنظيف) ما إذا كان يجب تشغيل هذا القسم.
على سبيل المثال ، إذا قام المستخدم بتكوين البرنامج لتجاوز "Action_Name" من ، بعد تقييم Scope () ، سيتم تنفيذ do_some_other_stuff () دون استدعاء do_something () أولاً.
حاولت القيام بذلك باستخدام مدير السياق هذا:

@contextmanager
def scope(action):
  if action != 'bypass':
    yield

لكن حصلت RuntimeError: generator didn't yield استثناء (متى action هو 'bypass').
أبحث عن طريقة لدعم هذا دون العودة إلى التنفيذ الاختياري الأكثر مطولاً:

with scope('action_name') as s:
  if s.should_run():
    do_something()
    ...
do_some_other_stuff()

هل يعرف أحد كيف يمكنني تحقيق ذلك؟
شكرًا!

ملاحظة أنا أستخدم Python2.7

تعديل:
لا يتعين على الحل بالضرورة الاعتماد عليه with صياغات. أنا فقط لم أكن أعرف بالضبط كيف أعبر عنها بدونها. في جوهرها ، أريد شيئًا في شكل سياق (دعم الإعداد والتنظيف التلقائي ، لا علاقة له بالمنطق المحتوى) والسماح بالتنفيذ الشرطي بناءً على المعلمات التي يتم تمريرها إلى طريقة الإعداد وتحديدها في التكوين.
لقد فكرت أيضًا في حل ممكن باستخدام الديكورات. مثال:

@scope('action_name') # if 'action_name' in allowed actions, do:
                      #   setup()
                      #   do_action_name()
                      #   cleanup()
                      # otherwise return
def do_action_name()
  do_something()

لكنني لا أريد تطبيق الكثير من الهيكل الداخلي (أي ، كيف يتم تقسيم الكود إلى وظائف) بناءً على هذه النطاقات.
هل لدى أي شخص بعض الأفكار الإبداعية؟

هل كانت مفيدة؟

المحلول

أنت تحاول تعديل السلوك المتوقع لبناء اللغة الأساسية. هذه ليست فكرة جيدة أبدًا ، إنها ستؤدي فقط إلى الارتباك.

لا حرج في عملك ، ولكن يمكنك تبسيطه قليلاً.

@contextmanager 
def scope(action): 
  yield action != 'bypass'

with scope('action_name') as s: 
  if s: 
    do_something() 
    ... 
do_some_other_stuff() 

لك scope يمكن بدلاً من ذلك أن يكون فئة __enter__ الطريقة تُرجع إما كائن مفيد أو None وسيتم استخدامه بنفس الطريقة.

نصائح أخرى

يبدو أن ما يلي يعمل:

from contextlib import contextmanager

@contextmanager
def skippable():
    try:
        yield
    except RuntimeError as e:
        if e.message != "generator didn't yield":
            raise

@contextmanager
def context_if_condition():
    if False:
        yield True

with skippable(), context_if_condition() as ctx:
    print "won't run"

اعتبارات:

  • يحتاج شخص ما للتوصل إلى أسماء أفضل
  • context_if_condition لا يمكن استخدامه بدون skippable ولكن لا توجد طريقة لفرض ذلك/إزالة التكرار
  • يمكن أن يصطاد وقمع وقت التشغيل من وظيفة أعمق من المقصود (يمكن أن يساعد استثناء مخصص هناك ، ولكن هذا يجعل البناء كله أكثر فوضى)
  • إنه ليس أكثر وضوحًا من مجرد استخدام إصدار Ransom

لا أعتقد أن هذا يمكن القيام به. حاولت تنفيذ مدير سياق كصف وليس هناك طريقة ل فرض الكتلة لرفع استثناء من شأنه أن يتم سحقه لاحقًا __exit__() طريقة.

لدي نفس حالة الاستخدام مثلك ، وصادف مكتبة مشروطة أن شخص ما قد تطور بشكل مفيد في الوقت منذ أن نشرت سؤالك.

من الموقع ، استخدامه هو:

with conditional(CONDITION, CONTEXTMANAGER()):
    BODY()
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top