Чи має Python функцію "або дорівнює", наприклад || = у Ruby?


83

Якщо ні, то який найкращий спосіб це зробити?

Зараз я роблю (для проекту django):

if not 'thing_for_purpose' in request.session:
    request.session['thing_for_purpose'] = 5

але це досить незручно. У Ruby це буде:

request.session['thing_for_purpose'] ||= 5

що набагато приємніше.


23
Зверніть увагу, що ці два біти коду насправді дуже різні: версія Python встановлює йому значення 5, якщо його взагалі немає в дикті, де версія Ruby також встановлює значення 5, якщо встановлено будь-яке хибне значення.
Гленн Мейнард,

2
@Glenn, не дуже різний, але зовсім інший. Оскільки неініціалізоване хеш-значення повертає nil(false у логічному контексті), ця ідіома часто використовується саме для того, щоб її використовував sean. Ідіома працює лише тоді, якщо, звичайно, nilі falseне є законними цінностями в хеші (що дуже часто відповідає дійсності, тому ідіома в порядку)
horseyguy

8
@banister: Я не знаю, де можна провести межу між "дуже" і "цілком", але справа в тому, що це не рівнозначні твердження, і важливо зрозуміти різницю. (False дуже часто є допустимим значенням у хеші, який вкусить вас, коли ви хочете встановити за замовчуванням для логічного поля значення true; це суттєвий недолік ідіоми Рубі.)
Гленн Мейнард,

Так, приклад Python більше схожий на define-or , подібний до того, //=який ви знайдете в perl . Я думаю, що це ||=також походить від Perl.
draegtun

Ах, хороші бали, усі. Я не помітив цієї різниці.
Шон В.

Відповіді:


188

Прийнята відповідь хороша для диктовок, але заголовок шукає загальний еквівалент оператора Рубі || =. Поширеним способом зробити щось на зразок || = у Python є

x = x or new_value

36
Ця відповідь, швидше за все, шукають люди, які приходять сюди із пошуку Google.
gradi3nt

Це справді найкраща відповідь.
AdamC

6
Зауважте, що на відміну від Ruby, цей код працюватиме лише в тому випадку, якщо xвін був попередньо визначений (наприклад, встановлений Noneу методі ініціалізації класу).
oli

3
Правда, це поводиться не так, як Рубі || =. Ще одна річ, на яку слід звернути увагу, - це „правдивість” x. Якщо x == 0 в Python, ви отримаєте new_value, оскільки 0 вважається помилковим, а в Ruby ви отримаєте 0.
Джозеф Шіді

1
Це настільки ефективно, як || =? || = не виконує призначення, якщо воно не має значення null, але це завжди робить призначення. Чи компілятор python розумніший, ніж я думаю?
jsarma

17

dictмає setdefault().

Отже, якщо request.sessionє dict:

request.session.setdefault('thing_for_purpose', 5)

Нечітко схожий, але ні в чому не еквівалент Ruby's || =.
AdamC

1
Він суттєво відрізняється тим, що вираз за замовчуванням обчислюється, навіть якщо ключ вже встановлений. Неможливо вирішити вихідне питання, не оцінивши значення за замовчуванням, не отримавши доступ до ключа кілька разів, або обох.
slinkp

13

Точну відповідь: Ні Python не має один вбудований оператор , opякий може вилитися x = x or yв x op y.

Але це майже так. Побітовое або оператор-одно ( |=) волі функцію , як описано вище , якщо обидва операнда розглядається як булеві, із застереженням. (Що застереження? Звичайно, відповідь нижче.)

По-перше, основна демонстрація функціональності:

x = True
x    
Out[141]: True

x |= True
x    
Out[142]: True

x |= False
x    
Out[143]: True

x &= False
x    
Out[144]: False

x &= True
x    
Out[145]: False

x |= False
x    
Out[146]: False

x |= True
x   
Out[147]: True

Застереження полягає в тому, що python не є строго набраним, і, отже, навіть якщо значення обробляються як булеві значення у виразі, вони не будуть короткозамкнені, якщо їх передавати побітовому оператору. Наприклад, припустимо, у нас була логічна функція, яка очищає список і повертає, Trueякщо були видалені елементи:

def  my_clear_list(lst):
    if not lst:
        return False
    else:
        del lst[:]
        return True

Тепер ми можемо бачити короткозамкнену поведінку так:

x = True
lst = [1, 2, 3]
x = x or my_clear_list(lst)
print(x, lst)

Output: True [1, 2, 3]

Однак перемикання на orпобітове або ( |) усуває коротке замикання, тому функція my_clear_listвиконується.

x = True
lst = [1, 2, 3]
x = x | my_clear_list(lst)
print(x, lst)

Output: True []

Вище, x = x | my_clear_list(lst)еквівалентно x |= my_clear_list(lst).


10

Встановлення значення за замовчуванням має сенс, якщо ви робите це у проміжному програмному забезпеченні або щось інше, але якщо вам потрібно значення за замовчуванням у контексті одного запиту:

request.session.get('thing_for_purpose', 5) # gets a default

бонус: ось як насправді зробити ||=в Python.

def test_function(self, d=None):
    'a simple test function'
    d = d or {}

    # ... do things with d and return ...

1

Загалом, можна використовувати dict[key] = dict.get(key, 0) + val.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.