Какой самый Pythonic способ предоставить запасное значение в назначении? - PullRequest
19 голосов
/ 20 апреля 2009

В Perl часто приятно иметь возможность назначать объект, но указывать какое-либо запасное значение, если переменная, из которой назначается, - undef. Например:

my $x = undef;
my $y = 2;
my $a = $x || $y;

После этого

$a == 2

Есть ли краткий способ добиться этого в Python, если значение x равно None или будет полноценным ...

if x is not None
    a = x
else
    a = y

... будет ли самый Pythonic способ достичь этого?

РЕДАКТИРОВАТЬ: Извинения, как было отмечено несколькими комментаторами, я на самом деле не говорил о значении undefined, а о «undef» в Perl, что не совсем то же самое. Но вопрос, сформулированный изначально, не прояснил этого.

Ответы [ 9 ]

35 голосов
/ 20 апреля 2009

С 2.5:

Если вы хотите отступить только на нет:

a = x if x is not None else y 

Если вы хотите использовать пустую строку, false, 0 и т. Д .:

a = x if x else y 

или

a = x or y 

Что касается неопределенного (как никогда не определено, a.k.a. не связано):

try:
  a = x 
except NameError:
  a = y

или немного более хакерский (я бы не очень рекомендовал, но он короткий):

a = vars().get('x',y)
5 голосов
/ 20 апреля 2009

сначала вы можете сделать свой полный с тройной:

a = y if x is None else x

но это не решит твою проблему. то, что вы хотите сделать, более тесно реализовано:

try:
    a = x
except:
    a = y
4 голосов
/ 20 апреля 2009

Просто придирки к вашему примеру Perl:

my $x = undef;

Этот избыточный код можно сократить до:

my $x;

А следующий код не делает то, что вы говорите, он делает:

my $a = $x || $y;

Это фактически присваивает $ y $ a, когда $ x равен false . Ложные значения включают такие вещи, как undef, ноль и пустая строка. Чтобы проверить только определенность, вы можете сделать следующее (начиная с Perl 5.10):

my $a = $x // $y;
3 голосов
/ 20 апреля 2009

Я совершенно убежден, что нет «питонического» способа сделать это, потому что это не шаблон, который является питоническим. Элемент управления не должен достигать неопределенной ссылки на переменную в элегантном коде. Есть похожие идеи, которые питонны. Самое очевидное:

def myRange(start, stop=None):
    start, stop = (0, start) if stop is None else (start, stop)
    ...

Что важно, так это то, что stop определено в области видимости, но вызывающей стороне не нужно было передавать его явно, только то, что он принял значение по умолчанию, изменяя семантику аргументов, что фактически вызывает первый аргумент быть необязательным вместо второго, даже если язык не позволяет этого без этой хитрой уловки.

При этом, что-то вроде этого может следовать предпосылке без использования блока try-catch.

a = locals().get('x', y)
1 голос
/ 20 апреля 2009

Я думаю, что это поможет, так как проблема сводится к проверке, определена ли переменная или нет:
Простой способ проверить, что переменная определена в python?

1 голос
/ 20 апреля 2009

Есть троичная операция Python:

a = x if x is not None else y

Доступно в версии 2.5 и выше.

0 голосов
/ 20 апреля 2009

Один способ переписать ...

if x is not None
    a = x
else
    a = y

.. есть:

x = myfunction()

if x is None:
    x = y

print x

Или, используя исключения (возможно, больше Python'y, в зависимости от того, что делает код - если он возвращает None из-за ошибки, вероятно, использование исключения - правильный путь):

try:
    x = myfunction()
except AnException:
    x = "fallback"

print x

Все, что сказано, на самом деле нет ничего плохого в том, что вы оригинальный код:

if x is not None
    a = x
else
    a = y

Это долго, но я нахожу, что гораздо легче читать (и гораздо больше Pythonic), чем любой из следующих однострочников:

a = x if x is not None else y
a = x or y
0 голосов
/ 20 апреля 2009

Большинство решений основаны на том, что операторы не работают для случая, когда х равен 0 или отрицательно.

>>> x = 0
>>> y = 2
>>> a = x or y
>>> a
2
>>> 

Если вы знали имя переменной заранее, вы могли бы выглядеть так:

if 'x' in dir():
    a = x 
except:
     a =y

Однако это решение кажется мне небрежным. Я считаю, что лучший способ - использовать try, кроме блока, например:

try:
    a = x
else:
    a = y
0 голосов
/ 20 апреля 2009

Если это аргумент функции, вы можете сделать это:

def MyFunc( a=2 ):
    print "a is %d"%a

>>> MyFunc()
...a is 2
>>> MyFunc(5)
...a is 5

[Редактировать] Для downvoters ... бит if / else не нужен для решения - просто добавлен, чтобы сделать результаты ясными. Отредактировал его, чтобы удалить оператор if, если это делает его более понятным?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...