Эквивалент 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)