Пітонічний спосіб уникнути висловлювань "якщо x: повернути х"


218

У мене є метод, який викликає 4 інші методи послідовно, щоб перевірити конкретні умови, і повертається негайно (не перевіряючи наступні), коли кожен повертає щось Truthy.

def check_all_conditions():
    x = check_size()
    if x:
        return x

    x = check_color()
    if x:
        return x

    x = check_tone()
    if x:
        return x

    x = check_flavor()
    if x:
        return x
    return None

Це здається великим кодом багажу. Замість кожного 2-рядкового оператора if, я б зробив щось на зразок:

x and return x

Але це недійсний Python. Чи пропускаю тут просте вишукане рішення? До речі, у цій ситуації ці чотири методи перевірки можуть бути дорогими, тому я не хочу їх називати кілька разів.


7
Що це за х? Це просто True / False, або це структури даних, що містять певну інформацію, при цьому None або подібні використовуються як окремий випадок, щоб вказати на відсутність будь-яких даних? Якщо це останнє, ви майже напевно натомість використовуєте винятки.
Натаніел

13
@gerrit Код, представлений вище, є гіпотетичним / псевдокодом, який поза темою перегляду коду. Якщо автор публікації бажає переглянути їх реальний, фактичний робочий код , тоді так, вони можуть бути опубліковані в Code Review.
Франчіс

4
Чому, на вашу думку x and return x, краще if x: return x? Останнє набагато зручніше читати і, таким чином, ремонтувати. Ви не повинні занадто турбуватися про кількість символів або рядків; читабельність Вони все одно точно такі ж числа символів, які не є пробілами, і якщо ви дійсно повинні, вони if x: return xбудуть добре працювати лише в одному рядку.
marcelm

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

7
@ jpmc26 OP явно говорить про верні значення повернення, а потім його код повертається x(на відміну від нього bool(x)), так як він стоїть, я думаю, можна впевнено вважати, що функції ОП можуть повернути що завгодно, і він хоче спочатку все, що є правдою.
timgeb

Відповіді:


278

Ви можете використовувати цикл:

conditions = (check_size, check_color, check_tone, check_flavor)
for condition in conditions:
    result = condition()
    if result:
        return result

Це має додаткову перевагу в тому, що тепер ви можете зробити кількість умов змінними.

Ви можете використовувати map()+ filter()(версії Python 3, використовувати future_builtinsверсії в Python 2), щоб отримати перше таке відповідне значення:

try:
    # Python 2
    from future_builtins import map, filter
except ImportError:
    # Python 3
    pass

conditions = (check_size, check_color, check_tone, check_flavor)
return next(filter(None, map(lambda f: f(), conditions)), None)

але якщо це є більш зрозумілим - це дискусійне питання.

Інший варіант полягає у використанні генераторного виразу:

conditions = (check_size, check_color, check_tone, check_flavor)
checks = (condition() for condition in conditions)
return next((check for check in checks if check), None)

27
якщо умови насправді є лише умовами, тобто булевими, тоді у вашій першій пропозиції ви також можете використовувати вбудований anyзамість циклу. return any(condition() for condition in conditions)

4
@Leonhard: anyмає майже таку ж реалізацію всередині. Але це виглядає набагато краще, будь ласка, опублікуйте це як відповідь)
Нік Волинкін

13
Легкість читання нагадує майже всі інші міркування. Ви кажете, що карта / фільтр є "дискусійною", я голосую за незаперечно некрасивий. Дякую, звичайно, але якщо хтось із моєї команди поставив карту / фільтр для цього коду, я переклав би їх до іншої команди або призначив їх на постільну роботу.
Кевін Райс

15
Чи справді цей нечитабельний блок коду є "пітонічним"? І особливо ідея блискавки conditionsі arguments? Це IMHO набагато гірше, ніж оригінальний код, на розбір мого мозкового аналізатора потрібно близько 10 секунд.
yo

34
"Віддавайте перевагу Python", - сказали вони. "Perl не читається", - сказали вони. А потім це сталося: return next((check for check in checks if check), None).
jja

393

Як краща відповідь Мартійна, ви можете зав'язати ланцюжок or. Це поверне перше значення truthy, або Noneякщо немає значення truthy:

def check_all_conditions():
    return check_size() or check_color() or check_tone() or check_flavor() or None

Демонстрація:

>>> x = [] or 0 or {} or -1 or None
>>> x
-1
>>> x = [] or 0 or {} or '' or None
>>> x is None
True

9
Зрозуміло, але це швидко стане читати, якщо є кілька варіантів. Плюс мій підхід дозволяє використовувати різні умови.
Martijn Pieters

14
@MartijnPieters ви можете використовувати, \щоб поставити кожен чек у своєму власному рядку.
Caridorc

12
@MartijnPieters Я ніколи не мав на увазі, що моя відповідь краща за твою, мені подобається і твоя відповідь :)
timgeb

38
@Caridorc: Я сильно не люблю використовувати \розширення логічної лінії. Замість цього скористайтеся дужками; тому return (....)з новими рядками вставляються за потребою. Все-таки це буде одна довга логічна лінія.
Martijn Pieters

47
Я думаю, що це краще рішення. Аргумент "він набридне [..], якщо є декілька варіантів" є суперечливим, тому що одна функція в жодному разі не повинна робити непомірну кількість перевірок. Якщо це потрібно, перевірки слід розділити на кілька функцій.
BlueRaja - Danny Pflughoeft

88

Не змінюйте цього

Існують і інші способи зробити це, як показують різні відповіді. Жоден не такий чіткий, як ваш оригінальний код.


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

3
Це справді питання думки. Особисто я після цього видалив нові рядки :, тому що вважаю if x: return xце досить добре, і це робить функцію більш компактною. Але це може бути тільки я.
yo

2
Це не тільки ти. Використання orяк timgeb - це належна і добре зрозуміла ідіома. Багато мов мають це; можливо, коли його називають, orelseце ще зрозуміліше, але навіть звичайний старий or(або ||іншими мовами) мається на увазі як альтернатива спробувати, якщо перша "не працює".
Рей Тол

1
@RayToal: Імпорт ідіом з інших мов - чудовий спосіб придушити код.
Джек Едлі

1
Іноді так, точно! Також це може бути способом відкрити свою думку і привести її до відкриття нових і кращих зразків і парадигм, яких ніхто, можливо, не намагався раніше. Стиль розвивається людьми, які запозичують та діляться новими речами. Працює обома способами. У будь-якому разі, я ніколи не чув, щоб вживання orмаркованих не-пітонічних чи будь-яким чином затуманено, але все одно це питання думки --- як і належить.
Рей Тол

83

Насправді така ж відповідь, що і timgeb, але ви можете використовувати дужки для кращого форматування:

def check_all_the_things():
    return (
        one()
        or two()
        or five()
        or three()
        or None
    )

8
всі, будь ласка, допоможіть підняти цю відповідь до 1-го місця. зробіть свою участь!
Gyom

74

Відповідно до закону Керлі , ви можете зробити цей код більш читабельним, розділивши дві проблеми:

  • Які речі я перевіряю?
  • Чи повернулося одне?

на дві функції:

def all_conditions():
    yield check_size()
    yield check_color()
    yield check_tone()
    yield check_flavor()

def check_all_conditions():
    for condition in all_conditions():
        if condition:
            return condition
    return None

Це дозволяє уникнути:

  • складні логічні структури
  • дійсно довгі рядки
  • повторення

... зберігаючи лінійний, легкий для читання потік.

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


Мені це подобається, хоча True / False слід змінити на умову / None, щоб відповідати питанню.
Малькольм

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

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

1
Я думаю, цей підхід було б краще реалізувати з визначенням локальної функції.
Джек Едлі

1
@timgeb "Явне краще, ніж неявне", Дзен Пітона .
jpmc26

42

Це варіант першого прикладу Martijns. Він також використовує стиль "колекції дзвінків", щоб дозволити коротке замикання.

Замість циклу ви можете використовувати вбудований any.

conditions = (check_size, check_color, check_tone, check_flavor)
return any(condition() for condition in conditions) 

Зверніть увагу, що anyповертає булеве значення, тому якщо вам потрібно точне значення повернення чека, це рішення не працюватиме. anyНЕ буде розрізняти 14, 'red', 'sharp', 'spicy'як повертаються значення, всі вони будуть повернуті як True.


Ви можете зробити, next(itertools.ifilter(None, (c() for c in conditions)))щоб отримати фактичне значення, не відкидаючи його на булеве значення.
kojiro

1
Чи anyсправді коротке замикання?
zwol

1
@zwol Так, спробуйте це з деякими зразковими функціями або перегляньте docs.python.org/3/library/functions.html

1
Це менш читабельно, ніж зв'язування 4-х функцій з "або" і окупається лише в тому випадку, якщо кількість умов велике або динамічне.
rjh

1
@rjh Це чудово читабельно; це просто список буквально і розуміння. Я вважаю за краще, тому що мої очі глазурують приблизно після третьогоx = bar(); if x: return x;
Blacklight Shining

27

Ви думали просто написати if x: return xвсе в одному рядку?

def check_all_conditions():
    x = check_size()
    if x: return x

    x = check_color()
    if x: return x

    x = check_tone()
    if x: return x

    x = check_flavor()
    if x: return x

    return None

Це не менш повторюється, ніж у вас, але в IMNSHO він читається досить плавно.


24

Я дуже здивований, що ніхто не згадав про вбудований, anyякий зроблений для цієї мети:

def check_all_conditions():
    return any([
        check_size(),
        check_color(),
        check_tone(),
        check_flavor()
    ])

Зауважте, що хоча ця реалізація, мабуть, найясніша, вона оцінює всі перевірки, навіть якщо перша True.


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

def check_all_conditions():
    checks = [check_size, check_color, check_tone, check_flavor]
    return reduce(lambda a, f: a or f(), checks, False)

reduce(function, iterable[, initializer]): Застосовуйте функцію двох аргументів кумулятивно до елементів ітерабельного, зліва направо, щоб зменшити ітерабельність до одного значення. Лівий аргумент, x, - це накопичене значення, а правий аргумент, y - значення оновлення з ітерабельного. Якщо є необов'язковий ініціалізатор, він розміщується перед пунктами ітерабельного обчислення

У вашому випадку:

  • lambda a, f: a or f()це функція , яка перевіряє , що або акумулятор aабо поточний контроль f()є True. Зауважте, що якщо aце так True, f()не буде оцінено.
  • checksмістить функції перевірки ( fпредмет від лямбда)
  • False є початковим значенням, інакше перевірки не відбудеться і результат буде завжди True

anyі reduceє основними інструментами функціонального програмування. Я настійно закликаю вас навчити їх, а також, mapщо теж приголомшливо!


9
anyпрацює лише в тому випадку, якщо чеки насправді повертають булеве значення, буквально Trueабо False, але питання не вказує цього. Вам потрібно буде використовувати reduceдля повернення фактичного значення, поверненого чеком. Крім того, досить просто уникнути оцінки всіх перевірок anyза допомогою генератора, наприклад any(c() for c in (check_size, check_color, check_tone, check_flavor)). Як і у відповіді Леонарда
David Z

Мені подобається ваше пояснення та використання reduce. Як і @DavidZ, я вважаю, що у вашому рішенні anyслід використовувати генератор, і потрібно зазначити, що воно обмежується поверненням Trueабо False.
timgeb

1
@DavidZ насправді anyпрацює з truthy значеннями: any([1, "abc", False]) == Trueіany(["", 0]) == False
ngasull

3
@blint Вибачте, мені не було зрозуміло. Мета питання - повернути результат перевірки (а не просто вказати, вдалася чи не вдалася перевірка). Я вказував, що anyдля цієї мети працює лише тоді, коли фактичні булеві значення повертаються з функцій перевірки.
David Z

19

Якщо ви хочете однакову структуру коду, ви можете використовувати потрійні заяви!

def check_all_conditions():
    x = check_size()
    x = x if x else check_color()
    x = x if x else check_tone()
    x = x if x else check_flavor()

    return x if x else None

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

Демонстрація:

Знімок екрана


7
Що з маленькою рибою ASCII над вашим терміналом?

36
@LegoStormtroopr Я використовую шкаралупу риби, тому прикрашаю її акваріумом для риб Ascii, щоб зробити мене щасливим. :)
Фінет

3
Дякую за прекрасну рибу (і кольори, до речі, що це за редактор?)
mathreadler

4
Ви можете отримати рибу на fishshell.com , а конфігураційний файл для ascii тут pastebin.com/yYVYvVeK , також редактором є піднесений текст.
Фінет

9
x if x else <something>можна просто звести доx or <something>

5

Для мене найкраща відповідь - це від @ phil-frost, за яким слідує @ wayne-werner's.

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

Тому я змішував би відповідь @ PhilFrost з ідеєю збереження єдиного типу:

def all_conditions(x):
    yield check_size(x)
    yield check_color(x)
    yield check_tone(x)
    yield check_flavor(x)

def assessed_x(x,func=all_conditions):
    for condition in func(x):
        if condition:
            return x
    return None

Зауважте, що xпередається як аргумент, але також all_conditionsвикористовується як переданий генератор перевірочних функцій, де всі вони отримують xперевірку та повертають Trueабо False. За допомогою funcсall_conditions в якості значення за замовчуванням, ви можете використовувати assessed_x(x), або ви можете пройти далі персоналізований генератор через func.

Таким чином, ви отримуєте, xяк тільки проходить один чек, але він завжди буде одного типу.


4

В ідеалі я б переписав check_ функції для повернення Trueабо Falseзамість значення. Ваші чеки потім стають

if check_size(x):
    return x
#etc

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


3

Невелика різниця на першому прикладі Martijns вище, що дозволяє уникнути if всередині циклу:

Status = None
for c in [check_size, check_color, check_tone, check_flavor]:
  Status = Status or c();
return Status

Робить це? Ви все ще робите порівняння. У вашій версії ви також перевірите всі умови незалежно від того, і не повернете в першому екземплярі значення "truthy".
Reti43

4
@ Reti43: Status or c()буде пропускати / коротке замикання оцінювати дзвінки, c()якщо Statusце неправда, тому код у цій відповіді не викликає більше функцій, ніж код OP. stackoverflow.com/questions/2580136/…
Ніл Слейтер

2
@NeilSlater True. Єдиний недолік, який я бачу, полягає в тому, що найкращий випадок зараз знаходиться в O (n), тому що спискура повинна вийти n разів, коли раніше це було O (1), якщо перша функція повертає щось тривожне в O (1).
timgeb

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

3

Мені подобається @ timgeb's. Тим часом я хотів би додати, що вираження Noneв returnоператорі не потрібно, оскільки orоцінюється збір відокремлених висловлювань, і повертається перше значення "нуль", "порожнє", "жодне", і якщо такого немає, то Noneповертається чи єNone чи ні!

Отже, моя check_all_conditions()функція виглядає приблизно так:

def check_all_conditions():
    return check_size() or check_color() or check_tone() or check_flavor()

Використовуючи timeitз, number=10**7я переглянув час роботи ряду пропозицій. Для порівняння я просто використав random.random()функцію для повернення рядка або Noneна основі випадкових чисел. Ось весь код:

import random
import timeit

def check_size():
    if random.random() < 0.25: return "BIG"

def check_color():
    if random.random() < 0.25: return "RED"

def check_tone():
    if random.random() < 0.25: return "SOFT"

def check_flavor():
    if random.random() < 0.25: return "SWEET"

def check_all_conditions_Bernard():
    x = check_size()
    if x:
        return x

    x = check_color()
    if x:
        return x

    x = check_tone()
    if x:
        return x

    x = check_flavor()
    if x:
        return x
    return None

def check_all_Martijn_Pieters():
    conditions = (check_size, check_color, check_tone, check_flavor)
    for condition in conditions:
        result = condition()
        if result:
            return result

def check_all_conditions_timgeb():
    return check_size() or check_color() or check_tone() or check_flavor() or None

def check_all_conditions_Reza():
    return check_size() or check_color() or check_tone() or check_flavor()

def check_all_conditions_Phinet():
    x = check_size()
    x = x if x else check_color()
    x = x if x else check_tone()
    x = x if x else check_flavor()

    return x if x else None

def all_conditions():
    yield check_size()
    yield check_color()
    yield check_tone()
    yield check_flavor()

def check_all_conditions_Phil_Frost():
    for condition in all_conditions():
        if condition:
            return condition

def main():
    num = 10000000
    random.seed(20)
    print("Bernard:", timeit.timeit('check_all_conditions_Bernard()', 'from __main__ import check_all_conditions_Bernard', number=num))
    random.seed(20)
    print("Martijn Pieters:", timeit.timeit('check_all_Martijn_Pieters()', 'from __main__ import check_all_Martijn_Pieters', number=num))
    random.seed(20)
    print("timgeb:", timeit.timeit('check_all_conditions_timgeb()', 'from __main__ import check_all_conditions_timgeb', number=num))
    random.seed(20)
    print("Reza:", timeit.timeit('check_all_conditions_Reza()', 'from __main__ import check_all_conditions_Reza', number=num))
    random.seed(20)
    print("Phinet:", timeit.timeit('check_all_conditions_Phinet()', 'from __main__ import check_all_conditions_Phinet', number=num))
    random.seed(20)
    print("Phil Frost:", timeit.timeit('check_all_conditions_Phil_Frost()', 'from __main__ import check_all_conditions_Phil_Frost', number=num))

if __name__ == '__main__':
    main()

І ось результати:

Bernard: 7.398444877040768
Martijn Pieters: 8.506569201346597
timgeb: 7.244275416364456
Reza: 6.982133448743038
Phinet: 7.925932800076634
Phil Frost: 11.924794811353031

2

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

Основна ідея - raiseвиняток, коли одна з функцій оцінюється як істинна, і повертає результат. Ось як це може виглядати:

def check_conditions():
    try:
        assertFalsey(
            check_size,
            check_color,
            check_tone,
            check_flavor)
    except TruthyException as e:
        return e.trigger
    else:
        return None

Вам знадобиться assertFalseyфункція, яка створює виняток, коли один з викликаних функцій аргументу оцінює як істинний:

def assertFalsey(*funcs):
    for f in funcs:
        o = f()
        if o:
            raise TruthyException(o)

Сказане вище може бути змінено таким чином, щоб також було надано аргументи для оцінюваних функцій.

І звичайно вам буде потрібно TruthyExceptionсаме. Цей виняток передбачає те, objectщо викликало виняток:

class TruthyException(Exception):
    def __init__(self, obj, *args):
        super().__init__(*args)
        self.trigger = obj

Можна, звичайно, перетворити оригінальну функцію на щось більш загальне:

def get_truthy_condition(*conditions):
    try:
        assertFalsey(*conditions)
    except TruthyException as e:
        return e.trigger
    else:
        return None

result = get_truthy_condition(check_size, check_color, check_tone, check_flavor)

Це може бути трохи повільніше, оскільки ви використовуєте і ifоператор, і обробку винятку. Однак виняток обробляється лише максимум один раз, тому удар до продуктивності повинен бути незначним, якщо ви не розраховуєте запустити перевірку і отримати Trueзначення багато тисяч тисяч разів.


//, милий! Чи вважається "пітонічним" використовувати обробку винятків для подібних речей?
Натан Басанес

@NathanBasanese Звичайно, винятки використовуються для контролю потоку постійно. StopIterationє досить хорошим прикладом: виняток виникає щоразу, коли ви вичерпуєте його. Те, що ви хочете уникати, - це послідовно збирати винятки знову і знову, що стало б дорого. Але робити це один раз - це не так.
Рік підтримує Моніку

//, Ах, я вважаю, ви посилаєтесь на щось на кшталт programmers.stackexchange.com/questions/112463/… . Я проголосував за це питання і за цю відповідь. Документи Python 3 для цього є тут: docs.python.org/3/library/stdtypes.html#iterator-types , я думаю.
Натан Басанес

1
Ви хочете визначити функцію загального призначення та виняток, просто десь зробити кілька перевірок у якійсь іншій функції? Я думаю, це трохи.
Blacklight Shining

@BacklightShining Я згоден. Я ніколи насправді цього не робив би сам. ОП попросила способи уникнути повторного коду, але я думаю, що з нього він почав - це прекрасно.
Рік підтримує Моніку

2

Пітонічний спосіб - або використання скорочення (як хтось уже згадував), або itertools (як показано нижче), але мені здається, що просто використання короткого замикання orоператора створює чіткіший код

from itertools import imap, dropwhile

def check_all_conditions():
    conditions = (check_size,\
        check_color,\
        check_tone,\
        check_flavor)
    results_gen = dropwhile(lambda x:not x, imap(lambda check:check(), conditions))
    try:
        return results_gen.next()
    except StopIteration:
        return None

0

Я збираюся заскочити сюди і ніколи не написав жодного рядка Python, але я припускаю if x = check_something(): return x це дійсно?

якщо так:

def check_all_conditions():

    if (x := check_size()): return x
    if (x := check_color()): return x
    if (x := check_tone()): return x
    if (x := check_flavor()): return x

    return None

1
Це не дійсний Python, ні. Python не дозволяє використовувати такий оператор призначення. Однак новий вираз спеціального призначення було додано зовсім недавно, тому тепер можна писати if ( x := check_size() ) :для того ж ефекту.
Джек Едлі

0

Або скористайтеся max:

def check_all_conditions():
    return max(check_size(), check_color(), check_tone(), check_flavor()) or None

-2

У минулому я бачив кілька цікавих реалізацій операторів переключення / випадку з диктами, які привели мене до цієї відповіді. Використовуючи наведений приклад, ви отримаєте наступне. (Це божевілля using_complete_sentences_for_function_names, так check_all_conditionsвоно перейменовано status. Див. (1))

def status(k = 'a', s = {'a':'b','b':'c','c':'d','d':None}) :
  select = lambda next, test : test if test else next
  d = {'a': lambda : select(s['a'], check_size()  ),
       'b': lambda : select(s['b'], check_color() ),
       'c': lambda : select(s['c'], check_tone()  ),
       'd': lambda : select(s['d'], check_flavor())}
  while k in d : k = d[k]()
  return k

Функція select позбавляє від необхідності виклику кожного check_FUNCTIONразу двічі, тобто ви уникаєте check_FUNCTION() if check_FUNCTION() else nextдодавання іншого функціонального рівня. Це корисно для тривалих функцій. Лямбди в дикті затримують виконання його значень до циклу while.

В якості бонуса ви можете змінити порядок виконання і навіть пропустити деякі тести з зраджує kі , sнаприклад ,k='c',s={'c':'b','b':None} , зменшує кількість тестів і змінює первісний порядок обробки.

У timeitстипендіатів може торгуватися вартість додавання додаткового шару або два стека і вартість для Dict подивитися , але ви , здається , більше стурбовані красивості коду.

Крім того, більш простою реалізацією може бути наступне:

def status(k=check_size) :
  select = lambda next, test : test if test else next
  d = {check_size  : lambda : select(check_color,  check_size()  ),
       check_color : lambda : select(check_tone,   check_color() ),
       check_tone  : lambda : select(check_flavor, check_tone()  ),
       check_flavor: lambda : select(None,         check_flavor())}
  while k in d : k = d[k]()
  return k
  1. Я маю на увазі це не з точки зору pep8, а з точки зору використання одного стислого описового слова замість речення. Отриманий ОП може дотримуватися деякої конвенції кодування, працюючи з деякою існуючою базою коду або не піклуючись про стислі терміни в їхній кодовій базі.

1
Іноді люди справді божеволіють зі своїм найменуванням, коли це зробить одне слово. Використовуючи код прикладу ОП, навряд чи він би мав функції, які називаються, check_no/some/even/prime/every_third/fancy_conditionsале тільки ця одна функція, то чому б не викликати її statusчи якщо наполягати check_status. Використовувати _all_зайве, він не забезпечує цілісність всесвіту. Ім'я, безумовно, повинно використовувати послідовний набір ключових слів, використовуючи проміжки імен, коли це можливо. Довгі речення найкраще служать доктринами. Один рідко потребує більше 8-10 символів, щоб описувати щось коротко.
Карел

1
Я прихильник довгих імен функцій, тому що хочу, щоб функції вищого рівня були самодокументованими. Але check_all_conditionsце погана назва, тому що це не перевірка всіх умов, якщо одна правда. Я б використав щось подібне matches_any_condition.
Джон Хазен

Це цікавий такт. Я намагаюся мінімізувати кількість листів, які я буду робити друкарськими пізніше :) Здається, я перекинув купу думок у своє рішення, коли я справді намагався дати корисну підказку. Чи слід це редагувати?
Карел

2
Це здається занадто хитким, особливо враховуючи інші рішення цього питання. Те, що намагається зробити ОП, зовсім не є складним; рішення повинно бути досить простим, щоб зрозуміти напівсин. І я поняття не маю, що тут відбувається.
Blacklight Shining

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