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:
- an assigned OR operation
- an in-place OR operation
- 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:
- an assigned merge-right operation
- 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:
- an assigned union operation
- 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:
- an assigned bitwise OR operation
- 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":
- internally compare binary equivalents
- apply the operation
- 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 aMutableSet
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 thecomment
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 asArray.new
) => "ifmap[parent]
is undefined, initialize it withArray.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
Is the List of Python Reserved Words and Builtins Available in a Library
How to Sort Alpha Numeric Set in Python
Using Headers with the Python Requests Library's Get Method
How to Parse a Time String Containing Milliseconds in It with Python
Python Locale Error: Unsupported Locale Setting
Python Image Library Fails with Message "Decoder Jpeg Not Available" - Pil
What Are Some Good Python Orm Solutions
Set Background Color for Subplot
R Foverlaps Equivalent in Python
Combine a Folder of Text Files into a CSV with Each Content in a Cell
Reduce Number of Levels for Large Categorical Variables
Error When Installing Rpy2 Module in Python with Easy_Install
How to Take Partial Screenshot with Selenium Webdriver in Python