Як вийти із пункту if


104

Які існують способи передчасного виходу із ifпункту?

Бувають випадки, коли я пишу код і хочу помістити breakзаяву всередину ifпропозиції, тільки щоб пам’ятати, що вони можуть бути використані лише для циклів.

Візьмемо такий приклад:

if some_condition:
   ...
   if condition_a:
       # do something
       # and then exit the outer if block
   ...
   if condition_b:
       # do something
       # and then exit the outer if block
   # more code here

Я можу придумати один із способів зробити це: припускаючи, що випадки виходу трапляються всередині вкладених, якщо заяви, загортайте залишився код у великий ще блок. Приклад:

if some_condition:
   ...
   if condition_a:
       # do something
       # and then exit the outer if block
   else:
       ...
       if condition_b:
           # do something
           # and then exit the outer if block
       else:
           # more code here

Проблема з цим полягає в тому, що більше місць виходу означає більше гніздування / відступ коду.

Крім того, я можу написати свій код, щоб ifпропозиції були якомога меншими та не вимагали жодних виходів.

Хтось знає про хороший / кращий спосіб вийти із ifзастереження?

Якщо є якісь інші асоційовані пункти - якщо і ще, я вважаю, що вихід із них може пропуститись.


2
Для вашого другого зразка коду - ви знаєте про це elif?
Крейг МакКуін

2
"Крім того, я можу написати свій код, щоб параметри if були якомога меншими і не вимагали жодних виходів." - і, безумовно, це був би найкращий спосіб дій. :-)
Michał Marczyk

2
@Craig McQueen: Я так, але скажіть, що хотів виконати код між операторами умови? Напр. if a: #stuff; #stuff_inbetween; if b: #stuff;Код між між собою залежить, not aале не залежить від нього b.
Роман

привіт , будь ласка , не забудьте elif stackoverflow.com/a/2069680/7045119
kerbrose

Відповіді:


99

(Цей метод працює для ifs, декількох вкладених циклів та інших конструкцій, які ви не можете breakлегко отримати.)

Оберніть код у власній функції. Замість breakвикористання return.

Приклад:

def some_function():
    if condition_a:
        # do something and return early
        ...
        return
    ...
    if condition_b:
        # do something else and return early
        ...
        return
    ...
    return

if outer_condition:
    ...
    some_function()
    ...

4
Я радий додати до своєї сумки фокуси програміста. На мій досвід, такий підхід працює майже кожного разу, коли ви спокушаєтесь використовувати гото, що рухається вперед. (І він натякає на та вирішує ситуації, коли одна функція стає занадто великою)
Дрю Дорманн

2
В ідеалі ви можете домогтися і того, і іншого, але бувають випадки, коли ви повинні торгувати хорошим кодом для хорошої роботи. Ці часи трапляються рідко, особливо коли ви думаєте про використання Python. Іншими словами: не турбуйтеся так сильно за накладні виклики функцій.
ефемія

17
Є старий анекдот: "Денніс Рітчі заохочував модульність, розповідаючи всім і всім, що виклики функцій були дійсно, дуже дешеві в C. Усі почали писати невеликі функції та модулювати. Через роки ми з’ясували, що функціональні дзвінки все ще дорогі на PDP-11 , а код VAX часто витрачав 50% свого часу на інструкцію CALLS. Денніс збрехав нам! Але було вже пізно; нас усі зачепили ... "
проповідник

1
@ephemient: Це смішно, чи є ще історія? Я хотів би прочитати всю справу.
Роман

4
Ця цитата - з розділу 4 книги "Мистецтво програмування Unix" (онлайн за адресою faqs.org/docs/artu ). Ви дійсно повинні прочитати всю справу, якщо цього не зробили раніше.
ефемія

55
від goto import goto, мітка

якщо деякий_умова:
   ...
   якщо умова_а:
       # робити щось
       #, а потім вийдіть із зовнішнього блоку
       goto .end
   ...
   якщо умова_b:
       # робити щось
       #, а потім вийдіть із зовнішнього блоку
       goto .end
   # ще код тут

мітка .end

(Насправді не використовуйте це, будь ласка.)


35
+1, тому що це смішно. Пошук в Google виявив мені, що це жартівний жартівний модуль.
Роман

2
Я з цим теж пов’язав. Клацніть на першому goto.
ефеміент

1
це нагадує мені код складання з усіма видами розгалужень :)
phunehehe

2
@ephemient: Ах, не помітив посилання. Порахував, що це підкреслення коду. Але тепер, коли я дивлюсь на ваш код, я не бачу жодної реальної підсвітки ..
Роман

1
Коли PHP представив Гото я звернувся до Python php.net/manual/en/control-structures.goto.php
Marc

25
while some_condition:
   ...
   if condition_a:
       # do something
       break
   ...
   if condition_b:
       # do something
       break
   # more code here
   break

3
Ой, ей, мені дуже подобається ця ідея. Я думаю, що саме це вирішує моє первісне бажання. Однак у мене є нудотне відчуття, що це не є хорошою практикою (і з цієї причини я зараз зберігаю прийняту відповідь, оскільки це сприяє гарному стилю кодування).
Роман

6
Зауважте, що ви могли б зберегти оригінал, якщо і завернути всю річ у while True:. Просто переконайтеся, що ви ставите breakзаяву наприкінці! Для мов із конструкцією "час роботи" це робити більш ідентично:do { code that can conditionally break out } while (false);
Томас Едінг,

10

Ви можете імітувати функцію goto за винятком:

try:
    # blah, blah ...
    # raise MyFunkyException as soon as you want out
except MyFunkyException:
    pass

Відмова: Я маю на увазі лише донести до вашої уваги можливість робити такі дії, хоча я ні в якому разі не схвалюю це як розумне за звичайних обставин. Як я вже згадував у коментарі до питання, структурування коду таким чином, щоб уникнути візантійських умов в першу чергу є переважнішим на сьогоднішній день. :-)


Ха-ха, мені подобається це креативне рішення. Хоча я буду дотримуватися вашої відмови від відповідальності і не буду використовувати такий фанк-код.
Роман

@Roman: Радий додати ще один трюк поряд із Shmoopty's - навіть коли я порівняно почуваюся неслухняним. ;-)
Michał Marczyk

8

може бути це?

if some_condition and condition_a:
       # do something
elif some_condition and condition_b:
           # do something
           # and then exit the outer if block
elif some_condition and not condition_b:
           # more code here
else:
     #blah
if

1
Так, це могло б спрацювати. Я думаю, що мій розум затуманився, elifпоки я писав це. Хоча я думаю, що це не спрацює в ситуації, коли я хочу виконати код між вкладеними операторами if.
Роман

це насправді правильна відповідь. чому я не бачу, як люди рекомендують це ?? :)
kerbrose

6

Що стосується того, що насправді було запропоновано, мій підхід полягає в тому, щоб помістити їх ifвсередині петельового циклу

while (True):
    if (some_condition):
        ...
        if (condition_a):
            # do something
            # and then exit the outer if block
            break
        ...
        if (condition_b):
            # do something
            # and then exit the outer if block
            break
        # more code here
    # make sure it is looped once
    break

Перевірте:

conditions = [True,False]
some_condition = True

for condition_a in conditions:
    for condition_b in conditions:
        print("\n")
        print("with condition_a", condition_a)
        print("with condition_b", condition_b)
        while (True):
            if (some_condition):
                print("checkpoint 1")
                if (condition_a):
                    # do something
                    # and then exit the outer if block
                    print("checkpoint 2")
                    break
                print ("checkpoint 3")
                if (condition_b):
                    # do something
                    # and then exit the outer if block
                    print("checkpoint 4")
                    break
                print ("checkpoint 5")
                # more code here
            # make sure it is looped once
            break

1
Якщо чесно, це найчистіше рішення. Коли код потрібно вийти дуже зрозуміло - вам не доведеться турбуватися про розміщення функцій усередині функцій, і немає нульової продуктивності або логічного боргу.
Трент

2
Можна подумати про використання for _ in range(1):замість while True:. (1) Краще повідомте про свій намір провести один цикл ітерації та (2) відсутність останньої заяви про перерву для виходу з циклу (можливо, буде видалено пізніше випадково)
Бернхард Кауслер,

3

Взагалі кажучи, не варто. Якщо ви гніздите "ifs" і ламаєтесь від них, ви робите це неправильно.

Однак якщо вам потрібно:

if condition_a:
   def condition_a_fun():
       do_stuff()
       if we_wanna_escape:
           return
   condition_a_fun()
if condition_b:
   def condition_b_fun():
       do_more_stuff()
       if we_wanna_get_out_again:
           return
   condition_b_fun()

Зауважте, функції не мають бути оголошені в операторі if, вони можуть бути задекларовані заздалегідь;) Це було б кращим вибором, оскільки це дозволить уникнути необхідності перероджувати негарне, якщо / потім пізніше.


Дякую за відповідь. Я не впевнений, що ви маєте на увазі під "гніздовими петлями". Якщо ви маєте на увазі мою згадку про ключове слово 'break', я просто намагався мотивувати свій пошук if-exit, порівнюючи його з наявністю виходу з циклу. Крім того, я не впевнений, як ваш код вирішує проблему, як мій приклад мав if condition_aі if condition_bвклався всередині if some_condition. Я хочу, щоб я міг вирватися з if some_condition.
Роман

Причина, через яку люди хочуть гніздити ifs та ламати їх, ймовірно, не тому, що вони роблять це неправильно, а можливо тому, що хочуть написати чистий простий та DRY-код. простий випадок, коли програмі потрібно виконати x (), коли виконано і умова_a, і умова_b, і потрібно робити y () лише для умови_а, а z () робити лише для умови_b. а кодер відмовляється писати x () кілька разів
izzulmakin

1

Ефективно те, що ви описуєте, - це goto-висловлювання, які, як правило, досить сильно налаштовані. Ваш другий приклад набагато простіше зрозуміти.

Однак чистіше все-таки буде:

if some_condition:
   ...
   if condition_a:
       your_function1()
   else:
       your_function2()

...

def your_function2():
   if condition_b:
       # do something
       # and then exit the outer if block
   else:
       # more code here

1

Є ще один спосіб, який не покладається на визначення функцій (оскільки іноді це менш читабельно для невеликих фрагментів коду), не використовує додатковий зовнішній цикл while (який, можливо, потребуватиме особливої ​​оцінки в коментарях, щоб бути зрозумілим на перший погляд) , не використовує goto (...), і найголовніше, щоб ви зберегли рівень відступу для зовнішнього, якщо так вам не доведеться починати вкладати речі.

if some_condition:
   ...
   if condition_a:
       # do something
       exit_if=True # and then exit the outer if block
if some condition and not exit_if: # if and only if exit_if wasn't set we want to execute the following code
   # keep doing something
   if condition_b:
       # do something
       exit_if=True # and then exit the outer if block
if some condition and not exit_if:
   # keep doing something

Так, це також потребує другого пошуку для читабельності, однак, якщо фрагменти коду невеликі, це не вимагає відстеження циклів, які ніколи не повторяться, і після розуміння того, для чого проміжні ifs, це легко читається, все в одне місце і з однаковим відступом.

І це має бути досить ефективно.


0

Тож тут я розумію, що ви намагаєтеся вирватися із зовнішнього блоку коду

if some_condition:
    ...
    if condition_a:
       # do something
       # and then exit the outer if block
       ...
    if condition_b:
       # do something
       # and then exit the outer if block
# more code here

Вихід з цього полягає в тому, що ви можете перевірити наявність помилкового стану у зовнішньому блоці if, який потім неявно вийде з блоку коду, а потім використовувати блок else, щоб вкласти інший ifs, щоб зробити щось

if test_for_false:
    # Exit the code(which is the outer if code)

else:
    if condition_a:
        # Do something

    if condition_b:
        # Do something

0

Єдине, що застосувало б це без додаткових методів, це elifнаступний приклад

a = ['yearly', 'monthly', 'quartly', 'semiannual', 'monthly', 'quartly', 'semiannual', 'yearly']
# start the condition
if 'monthly' in b: 
    print('monthly') 
elif 'quartly' in b: 
    print('quartly') 
elif 'semiannual' in b: 
    print('semiannual') 
elif 'yearly' in b: 
    print('yearly') 
else: 
    print('final') 

-1

Ось ще один спосіб вирішити це. Він використовує один елемент для циклу, що дозволяє просто використовувати продовження. Це запобігає зайвій необхідності мати зайві функції без будь-якої причини. І додатково виключає потенційну нескінченну кількість циклів.

if something:
    for _ in [0]:
        # Get x
        if not x:
            continue

        # Get y
        if not y:
            continue

        # Get z
        if not z:
            continue

        # Stuff that depends on x, y, and z

-2

використання returnв умові if виводить вас з функції, так що ви можете використовувати return для розірвання умови if.


2
він хоче зламати функцію, якщо не вийти
StealthOne
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.