Ефективніше використовувати if-return-return чи if-else-return?


141

Припустимо, у мене є ifзаява з a return. З точки зору ефективності, чи повинен я використовувати?

if(A > B):
    return A+1
return A-1

або

if(A > B):
    return A+1
else:
    return A-1

Чи слід віддати перевагу тому чи іншому при використанні компільованої мови (C) або сценарію (Python)?


11
У мові компіляції вам не потрібно сильно турбуватися про ефективність. Компілятор розбирає це. Ви повинні написати свій код, щоб ви могли його прочитати. (Ви все ще повинні турбуватися про ефективність своїх алгоритмів, а неохайне використання типів тощо вплине на ефективність - ви просто не турбуєтеся про свій стиль занадто багато.) Я не знаю про Python.
Ams

5
Розраховувати свій компілятор, щоб розібратися з кодом, є небезпечним кроком - і вимагає непогрішного компілятора. Краще, якщо ви знаєте, хто хоче, щоб ваш код робив!
Андрій

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

7
Як це можна закрити на основі думки? Це може бути думка після того, як ви дізнаєтесь, що різниці між продуктивністю між ними немає. Я цього не робив, і я майже впевнений, що багато людей теж цього не зробили.
Хорхе Лейтао

1
Незважаючи на те, що питання досить популярне, на нього не можна точно відповісти, не маючи на увазі конкретної мови, інакше відповідь на всі мови буде занадто довгим для цього формату.
Еміль Бержерон

Відповіді:


195

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

Ефективність обох форм порівнянна, базовий машинний код повинен виконувати стрибок, якщо ifумова все-таки помилкова.

Зауважте, що Python підтримує синтаксис, який дозволяє використовувати лише один returnвислів у вашому випадку:

return A+1 if A > B else A-1

32
C теж підтримує це. return (A>B)?A+1:A-1;Однак від написання такого коду абсолютно не виграє продуктивність . Все, що ми домоглися, - це зробити код затуманений, нечитабельним і в деяких випадках більш вразливим до рекламних акцій неявного типу.
Лундін

47
@Lundin заплутався? нечитабельна? Тільки для тих, хто не знає термінального оператора.
glglgl

6
@Lundin Після цього аргументацію, <погана практика , тому що -1 < 1uдає несподіваний результат.
glglgl

3
@glglgl: Ні, тому що люди очікують, що оператор ?: поводитиметься так, як інакше, що не відповідає дійсності. Якби хтось написав подібний код -1 < 1u, у якому я сумніваюся, він легко помітить помилку. Дуже багато людей написали б якусь версію коду, яку я опублікував. Я часто бачив такі помилки у виробничому коді, щоб довіряти оператору?:. Крім того, як правило, якщо мова дає два різні способи зробити те саме, використовуйте лише один із них, не вибирайте випадково жодного з двох, залежно від вашого настрою.
Лундін

6
@Lundin, що це аргумент для обережності з?: В C, але, здається, ви говорите, що це стосується і Python. Чи можете ви вказати на якісь приклади, коли використання тернару в Python призводить до несподіваних результатів?
LVC

33

З посібника зі стилю Chromium :

Не використовуйте інше після повернення:

# Bad
if (foo)
  return 1
else
  return 2

# Good
if (foo)
  return 1
return 2

return 1 if foo else 2

1
Дякую. +1. Чи можу я запитати, чому після повернення не користуватися іншим?
Тим

1
if-else функціонально еквівалентний, але це багатослівний. Інше зайве.
skeller88

17
Я був здивований, тому що перший здається більш зрозумілим і, отже, кращим.
Тім

4
Ви можете зробити розумну справу для будь-якого. Найголовніше в цьому рішенні IMO - це бути узгодженим у кодовій базі.
skeller88

2
Ви, мабуть, у більшості випадків виявите, що if-else-returnгілки майже ніколи не дорівнюють (якщо вони є, то вам все одно слід рефакторинг; або за допомогою switchконструкції, або для Python, перерахування дикту / використання дзвінка / тощо). Тому майже всі if-else-returnвипадки запобіжних застережень, і вони завжди перевіряються (знущаються над випробуваним виразом) без цього else.
коуберт

5

Що стосується стилю кодування:

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

(Хоча особисто я б сказав, що є кілька випадків, коли кілька заяв про повернення мають сенс: аналізатори протоколів тексту / даних, функції з обширною обробкою помилок тощо)

Консенсус усіх цих галузевих стандартів кодування полягає в тому, що вираз слід писати так:

int result;

if(A > B)
{
  result = A+1;
}
else
{
  result = A-1;
}
return result;

Щодо ефективності:

Наведений вище приклад та два приклади у питанні - цілком еквівалентні за ефективністю. Машинний код у всіх цих випадках має порівнювати A> B, потім розгалужувати або A + 1, або A-1 обчислення, а потім зберігати результат цього в регістрі процесора або в стеці.

Редагувати:

Джерела:

  • MISRA-C: правило 14.7 2004 року, яке в свою чергу цитує ...:
  • IEC 61508-3. Частина 3, таблиця В.9.
  • IEC 61508-7. С.2.9.

37
Ви впевнені, що релігія з одним поверненням заразила більшість стандартів кодування? Це було б страшно.
Даніель Фішер

7
Я б сказав, що правило не має сенсу більшість часу. Я, як правило, знаходжу код, який читається і простіше прослідкувати за поверненнями у відповідних точках Але це тільки я. Однак я думав про стандарти кодування компанії / проекту, а не такі речі, як MISRA, де в іншому випадку ідіотичні приписи можуть іноді мати певні заслуги. Я сподіваюсь, що більшість не придбали ідею єдиної точки виходу.
Даніель Фішер

3
@DanielFischer: У стандарті кодування C на основі MISRA, який я розробив для своєї компанії, у мене діє правило "Функція повинна мати лише одну точку виходу, в кінці функції, якщо тільки одна точка виходу не робить код менш читабельний ". Отже, це MISRA-C, але за винятком цього правила. Якщо ви пишете розширену функцію парсера, яка може повернути, скажімо, 10 різницьких помилок, рівень вкладених дужок зробить код абсолютно нечитабельним - у такому випадку було б розумнішим повернутися негайно, коли з’явиться помилка.
Лундін

6
Дивіться це питання ПС для обговорення та подальші посилання на подальші обговорення питання про єдину точку виходу. Окрім того, що правило єдиної точки виходу є старомодним та надмірно "інженерним", Python спеціально просуває "плоский краще, ніж вкладений" погляд , і розміщення, return де це стане зрозуміло, є ідіоматичним способом зробити це в Python.
Джон Y

1
@percebus Я повністю погоджуюся і цикломатична складність є хорошим аргументом проти єдиного повернення. І я вже декілька разів замислювався над комітетом MISRA, наприклад, це бачу . Принаймні, правило було переведено на рекомендаційний в MISRA-C: 2012.
Лундін

3

З будь-яким розумним компілятором не слід спостерігати за різницею; їх слід скласти до ідентичного машинного коду, оскільки вони еквівалентні.


2

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

За вибором я використовую:

return A+1 if (A > B) else A-1

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

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

Деякі плакати згадують про швидкість роботи. Швидкість виконання часу для мене є другорядним, оскільки якщо вам потрібна швидкість виконання, Python - це не найкраща мова. Я використовую Python як важливу для мене ефективність кодування (тобто написання коду без помилок).


1
Якщо користувач збирається голосувати за мою відповідь, я буду вдячний за коментар, чому вони вважають, що я помиляюся.
Стівен Елвуд

Я, мабуть, тільки рядок раніше, щоб зробити це 1 рядок на кожну заяву з метою читабельності. var n = 1 if (A > B) else -1 return A+n
перцепс

@percebus в деяких випадках погоджуюся, якщо ім'я змінної може посилити значення. Наприклад: 'code' move_x = 1, якщо my_x <противник_x else -1 # рухатися до опонента
Стівен Елвуд

До речі, я насправді підтримав вашу відповідь. Якщо ви бачите, що моя відповідь досить схожа
сприймайте

2

Я особисто уникаю elseблоків, коли це можливо. Дивіться кампанію "Анти-якщо"

Крім того, вони не стягують додаткову плату за лінію, знаєте: p

"Просте краще, ніж складне" та "Читання - це королевиця"

delta = 1 if (A > B) else -1
return A + delta

2
Чому голосування проти? Це "пітонічна" відповідь. Ви не можете вважати це бажаною відповіддю. Але не є недійсним. Я також
слідую

3
Я підтримав вашу відповідь, оскільки для мене вона набирає читабельності та простоти. Мене особисто вважають образливим, коли хтось мене озвучує, не навчаючи мене, чому моя відповідь є активно негативною.
Стівен Елвуд

1
Раніше не чула про кампанію "Анти-якщо", але може зрозуміти, чому "ІФ" може бути небезпечним. Я завжди намагаюся обмежити кількість коду, доданого до оператора if, і намагаюся переписати дерева elif для використання dict. Це, однак, стає трохи поза темою.
Стівен Елвуд

1
@StephenEllwood Використання dicts, щоб уникнути розбіжностей, дуже погана ідея.
Бахсау

@Bachsau Ви, мабуть, праві. Мені ніколи не доводилося турбуватися про продуктивність, оскільки всі мої сценарії працюють за секунди. Для мене читабельність, як правило, перемагає ефективність. Оскільки я не штатний програміст; вони просто засіб для досягнення мети.
Стівен Елвуд

1

Версія A простіша, і саме тому я б її використав.

І якщо ви ввімкнете всі попередження компілятора на Java, ви отримаєте попередження про другу версію, тому що це зайве і не має складності коду.


1

Я знаю, що питання позначене python, але в ньому згадуються динамічні мови, тому я подумав, що я повинен зазначити, що в рубі, якщо оператор if має фактичний тип повернення, щоб ви могли зробити щось на зразок

def foo
  rv = if (A > B)
         A+1
       else
         A-1
       end
  return rv 
end

Або тому, що воно також має неявне повернення просто

def foo 
  if (A>B)
    A+1
  else 
    A-1
  end
end

яка обходить проблему стилю, не маючи декількох повернень досить добре.

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