У меня есть метод, который вызывает 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
Это похоже на большой багажный код. Вместо каждого двухстрочного оператора if я бы предпочел сделать что-то вроде:
x and return x
Но это неверный Python. Я скучаю по простому, элегантному решению здесь? Кстати, в этой ситуации эти четыре метода проверки могут быть дорогими, поэтому я не хочу вызывать их несколько раз.
python
if-statement
Бернард
источник
источник
x and return x
лучше, чемif x: return x
? Последний гораздо более читабелен и, следовательно, удобен в обслуживании. Вам не нужно слишком беспокоиться о количестве символов или строк; удобочитаемость имеет значение. В любом случае, это точно такое же количество непробельных символов, и, если вам действительно нужно, ониif x: return x
будут отлично работать только на одной строке.x
(в противоположностьbool(x)
), так что я думаю, что можно с уверенностью предположить, что функции OP могут возвращать что угодно, и он хочет в первую очередь все, что является правдивым.Ответы:
Вы можете использовать цикл:
Это дает дополнительное преимущество: теперь вы можете изменять число условий.
Вы можете использовать
map()
+filter()
(версии Python 3, используйтеfuture_builtins
версии в Python 2), чтобы получить первое такое соответствующее значение:но если это более читаемым спорно.
Другой вариант - использовать выражение генератора:
источник
any
вместо цикла.return any(condition() for condition in conditions)
any
имеет почти такую же реализацию внутри. Но это выглядит намного лучше, пожалуйста, отправьте это как ответ)conditions
иarguments
? Это ИМХО намного хуже, чем оригинальный код, который занимает около 10 секунд, чтобы проанализировать мой анализатор мозгов.return next((check for check in checks if check), None)
.В качестве альтернативы хорошему ответу Мартина, вы можете зацепить
or
. Это вернет первое истинное значение, илиNone
если нет истинного значения:Демо-версия:
источник
\
чтобы поставить каждую проверку в отдельной строке.\
для расширения логической линии. Вместо этого используйте круглые скобки; такreturn (....)
с новыми строками, вставленными по необходимости. Тем не менее, это будет одна длинная логическая линия.Не меняй
Есть другие способы сделать это, как показывают различные другие ответы. Ни один не так ясен, как ваш оригинальный код.
источник
:
, потому что я считаю,if x: return x
что это довольно хорошо, и это делает функцию более компактной. Но это может быть только я.or
как сделал тимгеб, является правильной и понятной идиомой. У многих языков есть это; возможно, когда он вызывается,orelse
это даже более ясно, но даже старыйor
(или||
на других языках) подразумевается как альтернатива, если первый «не работает».or
помеченного непифонического или каким-либо образом запутанного, но это вопрос мнения в любом случае - как и должно быть.По сути, тот же ответ, что и у Timgeb, но вы можете использовать круглые скобки для лучшего форматирования:
источник
Согласно закону Керли , вы можете сделать этот код более читабельным, разделив две задачи:
на две функции:
Это позволяет избежать:
... сохраняя линейный, легко читаемый поток.
Вы также можете придумать еще лучшие имена функций, в зависимости от ваших конкретных обстоятельств, которые делают его еще более читабельным.
источник
return None
этом нет необходимости, поскольку функции возвращаютсяNone
по умолчанию. Тем не менее, нет ничего плохого в том, чтобы вернутьсяNone
явно, и мне нравится, что вы решили это сделать.Это вариант первого примера Мартинса. Он также использует стиль "коллекции вызываемых", чтобы обеспечить короткое замыкание.
Вместо цикла вы можете использовать встроенный
any
.Обратите внимание, что
any
возвращается логическое значение, поэтому, если вам нужно точное возвращаемое значение чека, это решение не будет работать.any
не будет различать14
,'red'
,'sharp'
,'spicy'
как возвращаемые значения, все они будут возвращены какTrue
.источник
next(itertools.ifilter(None, (c() for c in conditions)))
чтобы получить фактическое значение, не приводя его к логическому значению.any
короткое замыкание?x = bar(); if x: return x;
Рассматривали ли вы просто писать
if x: return x
все в одну строку?Это не менее повторяюще, чем то, что вы имели, но IMNSHO читается немного более плавно.
источник
Я весьма удивлен, что никто не упомянул встроенное,
any
которое сделано для этой цели:Обратите внимание, что хотя эта реализация, вероятно, является самой ясной, она оценивает все проверки, даже если первая из них
True
.Если вам действительно нужно остановиться на первой неудачной проверке, рассмотрите возможность использования
reduce
которой для преобразования списка в простое значение:В твоем случае:
lambda a, f: a or f()
это функция , которая проверяет , что либо аккумуляторa
или текущий контрольf()
являетсяTrue
. Обратите внимание, что еслиa
естьTrue
,f()
не будет оцениваться.checks
содержит функции проверки (f
элемент из лямбды)False
является начальным значением, иначе проверка не произойдет, и результат всегда будетTrue
any
иreduce
являются основными инструментами для функционального программирования. Я настоятельно рекомендую вам обучить их, а такжеmap
это здорово!источник
any
работает только в том случае, если проверки действительно возвращают логическое значение, буквальноTrue
илиFalse
, но вопрос не определяет это. Вам нужно будет использовать,reduce
чтобы вернуть фактическое значение, возвращаемое чеком. Также достаточно просто избежать оценки всех проверок сany
помощью генератора, напримерany(c() for c in (check_size, check_color, check_tone, check_flavor))
. Как и в ответе Леонардаreduce
. Как и @DavidZ, я считаю, что ваше решениеany
должно использовать генератор, и нужно указать, что оно ограничено возвратомTrue
илиFalse
.any
работает с правдивыми значениями:any([1, "abc", False]) == True
andany(["", 0]) == False
any
для этой цели работает , только если из функций проверки возвращены действительные логические значения.Если вам нужна та же структура кода, вы можете использовать троичные операторы!
Я думаю, это выглядит красиво и понятно, если вы посмотрите на это.
Демо-версия:
источник
x if x else <something>
можно просто уменьшить доx or <something>
Для меня лучший ответ - ответ @ phil-frost, за которым следует @ wayne-werner.
Что мне кажется интересным, так это то, что никто ничего не сказал о том факте, что функция будет возвращать много разных типов данных, что сделает обязательным выполнение проверок самого типа x для дальнейшей работы.
Поэтому я бы смешал ответ @ PhilFrost с идеей сохранить один тип:
Обратите внимание, что
x
он передается как аргумент, но такжеall_conditions
используется как переданный генератор проверяющих функций, где все они получаютx
проверяемый объект и возвращаютTrue
илиFalse
. При использованииfunc
с вall_conditions
качестве значения по умолчанию, вы можете использоватьassessed_x(x)
, или вы можете пройти дальше персонализированный генератор черезfunc
.Таким образом, вы получите,
x
как только пройдет одна проверка, но она всегда будет одного типа.источник
В идеале я бы переписал
check_
функции для возвратаTrue
илиFalse
вместо значения. Ваши чеки становятсяПредполагая, что ваша
x
переменная не является неизменной, ваша функция все равно может изменить ее (хотя они не могут переназначить ее), но вызываемая функция наcheck
самом деле не должна изменять ее.источник
Небольшое изменение в первом примере Martijns выше, которое позволяет избежать if внутри цикла:
источник
Status or c()
будет пропускать / замыкать, оценивать вызовы,c()
еслиStatus
это правда, поэтому код в этом ответе, по-видимому, не вызывает больше функций, чем код OP. stackoverflow.com/questions/2580136/…Мне нравится @ Timgeb's. В то же время я хотел бы добавить, что выражение
None
вreturn
выражении не требуется, так какor
оценивается коллекция разделенных выражений и возвращается первое ненулевое, пустое, пустое и если не существует, тоNone
возвращается есть лиNone
или нет!Итак, моя
check_all_conditions()
функция выглядит так:Использование
timeit
сnumber=10**7
я посмотрел на время выполнения ряда предложений. Для сравнения я просто использовалrandom.random()
функцию для возврата строки илиNone
на основе случайных чисел. Вот весь код:И вот результаты:
источник
Этот способ немного нестандартен, но я думаю, что конечный результат прост, удобочитаем и выглядит красиво.
Основная идея заключается в
raise
исключении, когда одна из функций оценивается как верная и возвращает результат. Вот как это может выглядеть:Вам понадобится
assertFalsey
функция, которая вызывает исключение, когда один из аргументов вызываемой функции оценивается как истинный:Выше может быть изменено, чтобы также обеспечить аргументы для функций, которые будут оцениваться.
И конечно тебе понадобится
TruthyException
сама. Это исключение обеспечивает то,object
что вызвало исключение:Конечно, вы можете превратить оригинальную функцию во что-то более общее:
Это может быть немного медленнее, потому что вы используете как
if
оператор, так и обработку исключения. Однако исключение обрабатывается не более одного раза, поэтому снижение производительности должно быть незначительным, если вы не собираетесь запускать проверку и получатьTrue
значение много-много тысяч раз.источник
StopIteration
довольно хороший пример: исключение возникает каждый раз, когда вы исчерпываете итерацию. То, чего вы хотите избежать, - это последовательно поднимать исключения снова и снова, что будет дорогостоящим. Но делать это один раз нет.Питонический способ - это использовать redu (как кто-то уже упоминал) или itertools (как показано ниже), но мне кажется, что простое использование короткого замыкания
or
оператора дает более четкий кодисточник
Я собираюсь прыгнуть сюда и никогда не писал ни одной строки Python, но я предполагаю, что
if x = check_something(): return x
это правильно?если так:
источник
if ( x := check_size() ) :
для того же эффекта.Или используйте
max
:источник
В прошлом я видел несколько интересных реализаций операторов switch / case с диктовками, которые привели меня к этому ответу. Используя приведенный вами пример, вы получите следующее. (Это безумие
using_complete_sentences_for_function_names
, поэтомуcheck_all_conditions
переименовано вstatus
. См. (1))Функция выбора избавляет от необходимости вызывать каждый
check_FUNCTION
дважды, т.е. вы избегаетеcheck_FUNCTION() if check_FUNCTION() else next
добавления другого функционального слоя. Это полезно для долго работающих функций. Лямбды в dict задерживают выполнение его значений до цикла while.В качестве бонуса вы можете изменить порядок выполнения и даже пропустить некоторые тесты, изменив
k
и,s
например,k='c',s={'c':'b','b':None}
уменьшив количество тестов и отменив исходный порядок обработки.timeit
стипендиатов может торговаться стоимость добавления дополнительного слоя или два стека и стоимость для Dict посмотреть , но вы , кажется , больше озабочены красивости кода.Альтернативно, более простая реализация может быть следующей:
источник
check_no/some/even/prime/every_third/fancy_conditions
но только эту функцию, так почему бы не вызвать ееstatus
или если кто-то настаиваетcheck_status
. Использование_all_
излишне, он не обеспечивает целостность вселенных. При именовании обязательно следует использовать согласованный набор ключевых слов, используя, по возможности, интервал имен. Длинные предложения лучше всего служат строкой документов. Редко требуется более 8-10 символов для краткого описания чего-либо.check_all_conditions
это плохое имя, потому что оно не проверяет все условия, если они верны. Я бы использовал что-то вродеmatches_any_condition
.