Эквивалент Python Ruby || =

Чтобы проверить, существует ли переменная, а если выйдет, используйте исходное значение, другое - используйте новое назначенное значение. В рубине это var ||= var_new

Как записать его в python?

PS: Я не знаю name of ||=, я просто не могу выполнить поиск в Bing.

Ответы

Ответ 1

Я думаю, что существует некоторая путаница со стороны людей, которые на самом деле не уверены в том, что делает оператор условного присваивания (||=), а также некоторое недоразумение о том, как переменные порождаются в Ruby.

Каждый должен прочитать эту статью по этому вопросу. Цитата TL;DR:

Распространенное заблуждение состоит в том, что a || = b эквивалентно a = a || b, но ведет себя как || a = b

В a = a || b, a задается чем-то утверждением на каждом прогоне, тогда как с || a = b, a устанавливается только в том случае, если a логически ложно (т.е. если оно равно nil или false), поскольку || "короткое замыкание". То есть, если левая часть || сравнение верно, нет необходимости проверять правую сторону.

И еще одно очень важное замечание:

... присваивание переменной, даже если оно не выполняется, немедленно вызывает эту переменную.

# Ruby
x = 10 if 2 == 5
puts x

Несмотря на то, что первая строка не будет запущена, x будет существовать во второй строке, и никакое исключение не будет поднято.

Это означает, что Ruby будет абсолютно гарантировать, что существует контейнер переменных для значения, которое должно быть помещено, прежде чем будут иметься какие-либо правосторонние условия. ||= не присваивает, если a не определен, он присваивает, если a является ложным (опять же, false или nil - nil является значением по умолчанию ничтожества в Ruby), гарантируя a.

Что это значит для Python?

Ну, если a определено, следующее:

# Ruby
a ||= 10

фактически эквивалентен:

# Python
if not a:
    a = 10

в то время как следующее:

# Either language
a = a or 10

близок, но всегда присваивает значение, тогда как в предыдущих примерах нет.

И если a не определено, вся операция ближе к:

# Python
a = None
if not a:
    a = 10

Поскольку очень явный пример того, что a ||= 10 делает, когда a не определен, будет:

# Ruby
if not defined? a
    a = nil
end

if not a
    a = 10
end

В конце дня оператор ||= не полностью переводится на Python любым способом "Pythonic" из-за того, как он полагается на базовую переменную, которая нерестится в Ruby.

Ответ 2

В Python нет особенно элегантного способа, потому что не очень элегантно оказаться в ситуации, когда вы не знаете, существует ли переменная или нет. Тем не менее, это кажется самым близким:

try:
    var
except NameError:
    var = var_new

Я не знаком с оператором ||= в ruby, но из того, что вы описали, этот блок должен иметь правильное поведение. То есть мы оставляем var связанным как есть, как если бы это была уже существующая переменная, и в противном случае устанавливаем var_new.

Ответ 3

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

var = var or var_new

Правила Python для переменных, которые "не существуют", являются довольно строгими; это вызовет исключение, если var ранее не было назначено. Однако, если var оценивается как false, он получит значение var_new.

Я говорю, что это "идиоматически то, что вы хотите", потому что идиоматическая более крупная структура для такого рода вещей в Python выглядит так:

var1 = None
var2 = None
var3 = None

# ... code here that may or may not set var1 through var3 ...

var1 = var1 or "default1"
var2 = var2 or "default2"
var3 = var3 or "default3"

Отметим также, что Python имеет довольно широкое понятие "ложь". Эта конструкция действительна только в том случае, если var не может быть назначен ноль, False или любой объект, который считается "пустым" (например, "", [], {}...). Если вы действительно хотите, чтобы он срабатывал только на None, вам нужно написать более подробный

var = var if var is not None else var_new

и, вместо этого, я бы вообще искал другой способ решить большую проблему.

Наконец, если вы можете структурировать свой код, как это, вместо этого...

var1 = "default1"
var2 = "default2"
var3 = "default3"

# ... code here that may or may not set var1 through var3 ...

... тогда вы должны, потому что это будет короче и менее сложным в этом случае, а проблема None vs falsey полностью исключена.

Ответ 4

Не очень безопасно, но другой вариант:

var = locals().get('var', var_new)

Ответ 5

try: var
except NameError: var = var_new

или

var = locals().get('var', var_new)