Does Python Have an "Or Equals" Function Like ||= in Ruby

Does Python have an or equals function like ||= in Ruby?

Jon-Eric's answer's is good for dicts, but the title seeks a general equivalent to ruby's ||= operator.

A common way to do something like ||= in Python is

x = x or new_value

Python's equivalent of Ruby's ||=

I think there is some confusion from the people who aren't really sure what the conditional assignment operator (||=) does, and also some misunderstanding about how variables are spawned in Ruby.

Everyone should read this article on the subject. A TLDR quote:

A common misconception is that a ||= b is equivalent to a = a || b, but it behaves like a || a = b

In a = a || b, a is set to something by the statement on every run, whereas with a || a = b, a is only set if a is logically false (i.e. if it's nil or false) because || is 'short circuiting'. That is, if the left hand side of the || comparison is true, there's no need to check the right hand side.

And another very important note:

...a variable assignment, even if not run, immediately summons that variable into being.

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

Even though the first line won't be run, x will exist on the second line and no exception will be raised.

This means that Ruby will absolutely ensure that there is a variable container for a value to be placed into before any righthand conditionals take place. ||= doesn't assign if a is not defined, it assigns if a is falsy (again, false or nil - nil being the default nothingness value in Ruby), whilst guaranteeing a is defined.

What does this mean for Python?

Well, if a is defined, the following:

# Ruby
a ||= 10

is actually equivalent to:

# Python
if not a:
a = 10

while the following:

# Either language
a = a or 10

is close, but it always assigns a value, whereas the previous examples do not.

And if a is not defined the whole operation is closer to:

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

Because a very explicit example of what a ||= 10 does when a is not defined would be:

# Ruby
if not defined? a
a = nil
end

if not a
a = 10
end

At the end of the day, the ||= operator is not completely translatable to Python in any kind of 'Pythonic' way, because of how it relies on the underlying variable spawning in Ruby.

What does ||= (or-equals) mean in Ruby?

This question has been discussed so often on the Ruby mailing-lists and Ruby blogs that there are now even threads on the Ruby mailing-list whose only purpose is to collect links to all the other threads on the Ruby mailing-list that discuss this issue.

Here's one: The definitive list of ||= (OR Equal) threads and pages

If you really want to know what is going on, take a look at Section 11.4.2.3 "Abbreviated assignments" of the Ruby Language Draft Specification.

As a first approximation,

a ||= b

is equivalent to

a || a = b

and not equivalent to

a = a || b

However, that is only a first approximation, especially if a is undefined. The semantics also differ depending on whether it is a simple variable assignment, a method assignment or an indexing assignment:

a    ||= b
a.c ||= b
a[c] ||= b

are all treated differently.

What does |= (ior) do in Python?

|= performs an in-place+ operation between pairs of objects. In particular, between:

  • sets: a union operation
  • dicts: an update operation
  • counters: a union (of multisets) operation
  • numbers: a bitwise OR, binary operation

In most cases, it is related to the | operator. See examples below.

Sets

For example, the union of two assigned sets s1 and s2 share the following equivalent expressions:

>>> s1 = s1 | s2                                           # 1
>>> s1 |= s2 # 2
>>> s1.__ior__(s2) # 3

where the final value of s1 is equivalent either by:

  1. an assigned OR operation
  2. an in-place OR operation
  3. an in-place OR operation via special method++

Example

Here we apply OR (|) and the in-place OR (|=) to sets:

>>> s1 = {"a", "b", "c"}
>>> s2 = {"d", "e", "f"}

>>> # OR, |
>>> s1 | s2
{'a', 'b', 'c', 'd', 'e', 'f'}
>>> s1 # `s1` is unchanged
{'a', 'b', 'c'}

>>> # In-place OR, |=
>>> s1 |= s2
>>> s1 # `s1` is reassigned
{'a', 'b', 'c', 'd', 'e', 'f'}

Dictionaries

In Python 3.9+, new merge (|) and update (|=) operators are proposed between dictionaries. Note: these are not the same as set operators mentioned above.

Given operations between two assigned dicts d1 and d2:

>>> d1 = d1 | d2                                           # 1
>>> d1 |= d2 # 2

where d1 is equivalent via:

  1. an assigned merge-right operation
  2. an in-place merge-right (update) operation; equivalent to d1.update(d2)

Example

Here we apply merge (|) and update (|=) to dicts:

>>> d1 = {"a": 0, "b": 1, "c": 2}
>>> d2 = {"c": 20, "d": 30}

>>> # Merge, |
>>> d1 | d2
{"a": 0, "b": 1, "c": 20, "d": 30}
>>> d1
{"a": 0, "b": 1, "c": 2}

>>> # Update, |=
>>> d1 |= d2
>>> d1
{"a": 0, "b": 1, "c": 20, "d": 30}

Counters

The collections.Counter is related to a mathematical datastructure called a multiset (mset). It is basically a dict of (object, multiplicity) key-value pairs.

Given operations between two assigned counters c1 and c2:

>>> c1 = c1 | c2                                           # 1
>>> c1 |= c2 # 2

where c1 is equivalent via:

  1. an assigned union operation
  2. an in-place union operation

A union of multisets contains the maximum multiplicities per entry. Note, this does not behave the same way as between two sets or between two regular dicts.

Example

Here we apply union (|) and the in-place union (|=) to Counters:

import collections as ct

>>> c1 = ct.Counter({2: 2, 3: 3})
>>> c2 = ct.Counter({1: 1, 3: 5})

>>> # Union, |
>>> c1 | c2
Counter({2: 2, 3: 5, 1: 1})
>>> c1
Counter({2: 2, 3: 3})

>>> # In-place Union, |=
>>> c1 |= c2
>>> c1
Counter({2: 2, 3: 5, 1: 1})

Numbers

Lastly, you can do binary math.

Given operations between two assigned numbers n1 and n2:

>>> n1 = n1 | n2                                           # 1
>>> n1 |= n2 # 2

where n1 is equivalent via:

  1. an assigned bitwise OR operation
  2. an in-place bitwise OR operation

Example

Here we apply bitwise OR (|) and the in-place bitwise OR (|=) to numbers:

>>> n1 = 0
>>> n2 = 1

>>> # Bitwise OR, |
>>> n1 | n2
1
>>> n1
0

>>> # In-place Bitwise OR, |=
>>> n1 |= n2
>>> n1
1

Review

This section briefly reviews some bitwise math. In the simplest case, the bitwise OR operation compares two binary bits. It will always return 1 except when both bits are 0.

>>> assert 1 == (1 | 1) == (1 | 0) == (0 | 1)
>>> assert 0 == (0 | 0)

We now extend this idea beyond binary numbers. Given any two integral numbers (lacking fractional components), we apply the bitwise OR and get an integral result:

>>> a = 10 
>>> b = 16
>>> a | b
26

How? In general, the bitwise operations follow some "rules":

  1. internally compare binary equivalents
  2. apply the operation
  3. return the result as the given type

Let's apply these rules to our regular integers above.

(1) Compare binary equivalents, seen here as strings (0b denotes binary):

>>> bin(a)
'0b1010'
>>> bin(b)
'0b10000'

(2) Apply a bitwise OR operation to each column (0 when both are 0, else 1):

01010
10000
-----
11010

(3) Return the result in the given type, e.g. base 10, decimal:

>>> int(0b11010)
26

The internal binary comparison means we can apply the latter to integers in any base, e.g. hex and octal:

>>> a = 10                                   # 10, dec
>>> b = 0b10000 # 16, bin
>>> c = 0xa # 10, hex
>>> d = 0o20 # 16, oct

>>> a | b
26
>>> c | d
26

See Also

  • An example of overloading the __ior__() method to iterate iterables in a MutableSet abstract base class
  • R. Hettinger's OrderedSet recipe (see lines 3 and 10 respectively)
  • A thread on Python-ideas on why to use |= to update a set
  • A section B.8 of Dive in Python 3 on special methods of Python operators
  • In-place binary operators fallback to regular methods, see cpython source code (eval.c and abstract.c). Thanks @asotille.

+The in-place bitwise OR operator cannot be applied to literals; assign objects to names.

++Special methods return the same operations as their corresponding operators.

Does Swift have an “or equals” function like ||= in Ruby?

Such an operator was considered and rejected: https://github.com/apple/swift-evolution/blob/master/proposals/0024-optional-value-setter.md

The rational behind the rejection is supposed to be in the swift-evolution email list, but the link attached to the above points to SE-0025 instead of 24.

Here is the link to the rational (Edited because of Kenneth Bruno's comment blow): http://article.gmane.org/gmane.comp.lang.swift.evolution/7694

Understanding the || OR operator in If conditionals in Ruby

the exact semantics of || are:

  • if first expression is not nil or false, return it
  • if first expression is nil or false, return the second expression

so what your first expression works out to is, if @controller.controller_name == "projects", then the expression short-circuits and returns true. if not, it checks the second expression. the second and third variants are essentially if @controller.controller_name == "projects", since "projects" || "parts" equals "projects". you can try this in irb:

>> "projects" || "parts"
=> "projects"

what you want to do is

if ["projects", "parts"].include? @controller.controller_name

Can somenone translate this from Ruby to Python. Its a basic map function

So to answer your questions regarding operators like << or ||= []:

  • << appends an element to an array (or appends strings), in the case above it's used to append the comment object to either the results array or or the threaded thingy.
  • ||= basically means, if left-hand-side is undefined then evaluate & assign right-hand-side ([] is the same as Array.new) => "if map[parent] is undefined, initialize it with Array.new - else do nothing"

To method above creates an array with parent comments (results) and a hash with child comments (map).

What does ||= mean?

Basically, a ||= b means assign b to a if a is null or undefined or false (i.e. false-ish value in ruby), it is similar to a = b unless a, except it will always evaluate to the final value of a (whereas a = b unless a would result in nil if a was true-ish).

What does Ruby have that Python doesn't, and vice versa?

You can have code in the class definition in both Ruby and Python. However, in Ruby you have a reference to the class (self). In Python you don't have a reference to the class, as the class isn't defined yet.

An example:

class Kaka
puts self
end

self in this case is the class, and this code would print out "Kaka". There is no way to print out the class name or in other ways access the class from the class definition body in Python.

doubts regarding ||= OR EQUALS operator in ruby

In Ruby, there are two values that are considered logical false. The first is the boolean value false, the other is nil. Anything which is non-nil and not explicitly false is true. The first time though the method, @num is nil, which is treated as false and the logical or portion of ||= needs to be evaluated and ends up assigning the empty array to @num. Since that's now non-nil, it equates to true. Since true || x is true no matter what x is, in future invocations Ruby short circuits the evaluation and doesn't do the assignment.



Related Topics



Leave a reply



Submit