Как назначить переменную в IF, а затем вернуть ее? - PullRequest
12 голосов
/ 11 октября 2009
def isBig(x):
   if x > 4: 
       return 'apple'
   else: 
       return 'orange'

Это работает:

if isBig(y): return isBig(y)

Это НЕ работает:

if fruit = isBig(y): return fruit

Почему 2-й не работает !? Я хочу 1-лайнер. Кроме того, 1-й вызов вызовет функцию ДВАЖДЫ.

Как сделать из него 1 вкладыш, не вызывая функцию дважды?

Ответы [ 8 ]

16 голосов
/ 11 октября 2009

Я вижу, что кто-то уже указал на мой старый рецепт "назначить и установить", который сводится в простейшей версии к:

class Holder(object):
   def set(self, value):
     self.value = value
     return value
   def get(self):
     return self.value

h = Holder()

...

if h.set(isBig(y)): return h.get()

Однако это было предназначено главным образом для облегчения транслитерации между Python и языками, где назначение напрямую поддерживается в if или while. Если у вас есть «сотни» таких проверок и возвратов в каскаде, намного лучше сделать что-то совершенно другое:

hundreds = isBig, isSmall, isJuicy, isBlah, ...

for predicate in hundreds:
  result = predicate(y)
  if result: return result

или даже что-то вроде

return next(x for x in (f(y) for f in hundreds) if x)

если можно получить исключение StopIteration, если предикат не удовлетворен, или

return next((x for x in (f(y) for f in hundreds) if x)), None)

, если None - правильное возвращаемое значение, когда предикат не удовлетворен и т. Д.

Почти всегда, использование (или даже желание ;-) трюка / не-идиомы Holder - это «запах дизайна», который предлагает искать другой и более питонский подход - тот случай, когда Holder оправданным является именно тот особый случай, для которого я его разработал, т. е. случай, когда вы хотите сохранить тесное соответствие между кодом Python и некоторым не-Python (вы транслитерируете эталонный алгоритм в Python и хотите, чтобы он сначала работал, а затем рефакторинг его в более Pythonic форму, или вы пишете Python как прототип, который будет транслитерирован на C ++, C #, Java и т. д., как только он будет работать эффективно).

8 голосов
/ 11 октября 2009

Один вкладыш не работает, потому что в Python присваивание (fruit = isBig(y)) является оператором, а не выражением. В C, C ++, Perl и многих других языках это выражение, и вы можете поместить его в if или while или как вам угодно, но не в Python, потому что создатели Python думали, что это было слишком легко злоупотреблять (или злоупотреблять), чтобы писать «умный» код (как вы пытаетесь).

Кроме того, ваш пример довольно глупый. isBig() всегда будет иметь значение true, поскольку единственная строка, которая является ложной, является пустой строкой (""), поэтому ваш оператор if в этом случае бесполезен. Я предполагаю, что это просто упрощение того, что вы пытаетесь сделать. Просто сделайте это:

tmp = isBig(y)
if tmp: return tmp

Неужели это намного хуже?

2 голосов
/ 11 октября 2009

Если вы хотите кодировать в PHP (или C), код в нем. Не пытайтесь форсировать его методы на другом языке.

Одним из основных принципов Python (на мой взгляд) является его читаемость. Вы должны использовать:

fruit = isBig(y)
if fruit: return fruit

Я должен также упомянуть, что использование isXXX() очень странно; обычно используется для возврата логических значений. Особенно в том случае, когда вы используете его в выражении IF.

0 голосов
/ 27 апреля 2019

Начиная с Python 3.8 и введением выражений присваивания (PEP 572) (оператор :=), теперь можно захватить значение условия (isBig(y)) как переменную (* 1006) *) чтобы повторно использовать его в теле условия:

if x := isBig(y): return x
0 голосов
/ 05 апреля 2018

Вы можете использовать генератор:

def ensure(x):
    if x: yield x

for fruit in ensure(isBig(y)):
    return fruit
0 голосов
/ 30 октября 2013
print "apple" if x > 4 else "orange"
0 голосов
/ 11 октября 2009

Проблема в том, что операция присваивания не может быть оценена как имеющая логическое значение. Оператор if полагается на возможность вычисления логического значения. Например,

>>> fruit = 'apple'
>>> bool(fruit = 'apple')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

/Users/jem/<ipython console> in <module>()

TypeError: 'fruit' is an invalid keyword argument for this function
>>> bool('a')
True
0 голосов
/ 11 октября 2009

Это не работает из-за намеренного языкового дизайна, но вы можете использовать этот трюк , чтобы обойти это решение

...