Pythonic способ выбрать первую переменную, которая оценивается как True - PullRequest
5 голосов
/ 26 ноября 2009

У меня есть некоторые переменные, и я хочу выбрать первую, которая оценивается как True, или же вернуть значение по умолчанию.

Например, у меня есть a, b и c. Мой существующий код:

result = a if a else (b if b else (c if c else default))

Другой подход, который я рассматривал:

result = ([v for v in (a, b, c) if v] + [default])[0]

Но они оба чувствуют себя беспорядочно, так есть ли более питонский способ?

Ответы [ 7 ]

21 голосов
/ 26 ноября 2009

Вы имели в виду возвращение первого значения для чего bool(value)==True? Тогда вы можете просто полагаться на тот факт, что логические операторы возвращают последний оцененный аргумент :

result = a or b or c or default
17 голосов
/ 26 ноября 2009

Если одна переменная не «определена», вы не можете получить доступ к ее имени. Поэтому любая ссылка на «a» вызывает исключение NameError.

С другой стороны, если у вас есть что-то вроде:

a = None
b = None
c = 3

вы можете сделать

default = 1
r = a or b or c or default
# r value is 3
5 голосов
/ 26 ноября 2009

Пока default оценивается как Истина:

result = next((x for x in (a, b, c, d , e, default) if x))
2 голосов
/ 26 ноября 2009

Вы можете сделать что-то подобное (в отличие от других ответов, это решение, в котором у нет для определения «пропущенных» значений как None или False) :

b = 6
c = 8

def first_defined(items):
    for x in items:
        try:
            return globals()[x]
            break
        except KeyError:
            continue

print first_defined(["a", "b", "c"])

Чтобы избежать NameErrors, когда a, b или c не определены: передайте функции список строк вместо ссылок на переменные (вы не можете передавать несуществующие ссылки). Если вы используете переменные вне области действия 'globals ()', вы можете использовать getattr с аргументом по умолчанию.

-

Если a, b и c определены, я бы пошел на что-то подобное (учитывая тот факт, что пустая строка, None или False оценивается как логическое False):

a = None
b = 6
c = 8

def firstitem(items):
    for x in items:
        if x:
            return x
            break
        else:
            continue

print firstitem([a, b, c])
1 голос
/ 26 ноября 2009

Если под defined вы подразумеваете ever assigned any value whatsoever to in any scope accessible from here, то попытка получить доступ к «неопределенной» переменной вызовет исключение NameError (или некоторый его подкласс, но перехват NameError также отловит подкласс). Итак, самый простой способ выполнить, буквально, совершенно странную задачу, о которой вы спрашиваете, это:

for varname in ('a', 'b', 'c'):
  try: return eval(varname)
  except NameError: pass
return default

Любое предполагаемое решение, в котором отсутствует попытка / исключение, не будет работать в вышеприведенном значении для "определенного". Подходы, основанные на исследовании конкретных областей, будут либо пропускать другие области, либо будут довольно сложными, если попытаться воспроизвести логику упорядочивания областей, которую eval делает для вас так просто.

Если под «определенным» вы на самом деле имеете в виду «присвоенное значение, которое оценивается как истинное (в отличие от ложного)», т. Е. Все значения на самом деле определены (но может оказаться ложным, и вы вместо первого значения истинного значения), тогда уже предложенный a or b or c or default становится самым простым подходом. Но это совершенно другое (и даже более странное!) Значение слова «определено»! -)

1 голос
/ 26 ноября 2009

Как насчет этого?

a=None  
b=None  
c=None  
val= reduce(lambda x,y:x or y,(a,b,c,"default"))  
print val  

Вышеуказанные отпечатки "default". Если какой-либо из входов определен, val будет содержать первый определенный вход.

1 голос
/ 26 ноября 2009

Не знаю, работает ли это в каждом случае, но это работает для этого случая.

a = False
b = "b"
c = False
default = "default"
print a or b or c or default # b
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...