This question already has answers here:
Why doesn't the operator module have a function for logical or?
(3 answers)
Closed 6 years ago.
On the operator module, we have the or_ function, which is the bitwise or (|).
However I can't seem to find the logical or (or).
The documentation doesn't seem to list it.
I'm wondering why isn't it included? Is it not considered a operator?
Is there a builtin function that provides its behaviour?
The or operator short circuits; the right-hand expression is not evaluated when the left-hand returns a true value. This applies to the and operator as well; when the left-hand side expression returns a false value, the right-hand expression is not evaluated.
You could not do this with a function; all operands have to be evaluated before the function can be called. As such, there is no equivalent function for it in the operator module.
Compare:
foo = None
result = foo and foo(bar)
with
foo = None
result = operator.boolean_and(foo, foo(bar)) # hypothetical and implementation
The latter expression will fail, because you cannot use None as a callable. The first version works, because the and operator won't evaluate the foo(bar) expression.
The closest thing to a built-in or function is any:
>>> any((1, 2))
True
If you wanted to duplicate or's functionality of returning non-boolean operands, you could use next with a filter:
>>> next(operand for operand in (1, 2) if operand)
1
But like Martijn said, neither are true drop-in replacements for or because it short-circuits. A true or function would have to accept functions to be able to avoid evaluating all the results:
logical_or(lambda: 1, lambda: 2)
This is somewhat unwieldy, and would be inconsistent with the rest of the operator module, so it's probably best that it's left out and you use other explicit methods instead.
It's not possible:
This can explicitly be found in the docs:
The expression x or y first evaluates x; if x is true, its value is
returned; otherwise, y is evaluated and the resulting value is
returned.
It does not exist as an operator function because due to the language specification, it is impossible to implement because you cannot delay execution of a called argument when calling the function. Here is an example of or in action:
def foo():
return 'foo'
def bar():
raise RuntimeError
If bar is called, we get a Runtime error. And looking at the following line, we see that Python shortcuts the evaluation of the line, since foo returns a True-ish value.
>>> foo() or bar()
'foo'
We can approximate:
We can simulate this behavior by passing in uncalled functions, and then calling them inside our or function:
def my_or(*funcs):
for func in funcs:
call = func()
if call:
return call
return call
>>> my_or(foo, bar)
'foo'
But you cannot shortcut execution of called callables that are passed to a function:
>>> my_or(foo, bar())
Traceback (most recent call last):
File "<pyshell#28>", line 1, in <module>
like_or(foo, bar())
File "<pyshell#24>", line 2, in bar
raise RuntimeError
RuntimeError
So it would be improper to include such a function in the built-ins or standard library because users would expect an or function to work just as a boolean or test, which again, is impossible.
The reason you are getting 1 after executing >>> 1 or 2 is because 1 is true so the expression has been satisfied.
It might make more sense if you try executing >>> 0 or 2. It will return 2 because the first statement is 0 or false so the second statement gets evaluated. In this case 2 evaluates to a true boolean value.
The and and or operators evaluate the first value and then plug the result into the "AND and OR" truth tables. In the case of and the second value is only considered if the first evaluates to true. In the case of the or operator, if the first value evaluates to true the expression is true and can return, if it isn't the second value is evaluated.
Related
I am using python in operator with for loop and with if statement. My question is how is in implemented, that it behaves differently in this two cases: it iterates when using for loop and it checks if some element exists when using with if statement? Does this depend on implementation of for and if?
for i in x:
#iterates
if i in x:
#checks weather i in x or not
Membership testing with in is implemented via the method __contains__ (see Documentation). The different behaviour comes from the keyword before, for and if in your case.
Iteration with for is implemented such, that the method next is called and its return value is written to the iteration variable as long as the condition after the key word for is true. Membership testing in general is just a condition.
Code
A in B
Execution
B.__contains__(A) # returns boolean
Code
for A in B :
# Body
Execution
A = B.next()
if B.__contains__(A) :
# Body
A = B.next()
if B.__contains__(A) :
# Body
# ...
A = B.next()
if B.__contains__(A) :
# B.next() throws "StopIteration" if there is no more element
The keyword "in" in python solves different purposes based on "for" and "if". please look at this related link in stack overflow for more clarity
In many languages you'll find keywords that have multiple uses. This is simply an example of that. It's probably more helpful to think in terms of statements than thinking about the in keyword like an operator.
The statement x in y is a boolean-valued statement taking (assuming y is some appropriate collection) True if and only if the value of x is in the collection y. It is implemented with the __contains__ member function of y.
The statement for x in y: starts a loop, where each iteration x takes a different value from the collection y. This is implemented using the __iter__ member function of y and __next__ on the resulting iterator object.
There are other statements where the in keyword can appear, such as list comprehension or generator comprehension.
The reason is that for...in is something different from just in.
for x in y iterates over y.
if x in y calls y.__contains__(x).
The in keyword is an operator usually:
print(2 in [1, 2, 3]) # True
if 3 in range(7, 20):
print('3 in range!')
It corresponds to the object.__contains__ special method. The expression a in b corresponds to type(b).__contains__(a). Note that both a and b are names that are looked up.
In a for statement, in is not an operator. It is part of the for .. in .. syntax and separates the loop variable name from the iterable.
for thing in range(20):
print(thing) # thing is something else on each step
Note that for a in b only b is a name that is looked up. a is a name to bind to, similar to an assignment statement.
Python syntax has several constructs where the leading keyword defines the meaning of following keywords. For example, the as keyword has a different meaning in import and with:
# as aliases ExitStack
from contextlib import ExitStack as ContextStack
# as holds the result of ContextStack().__enter__()
with ContextStack() as stack:
...
It helps to think about such keywords not by implementation but by meaning. For example, a in b always means that "a is contained by b".
I have these two statements
return self.getData() if self.getData() else ''
and
return self.getData() or ''
I want to know are they same or there is any difference
I would say No because if self.getData() changes something during its operation, then the first statement has the possibility of returning a different result since it will make a 2nd call to it.
Maybe, but only if self.getData() is a pure function and has no side effects. More importantly the object that self.getData() returns must also be free of any side effects and consistently return a boolean value.
In the simplest case if f() is defined as:
def f():
return ["Hello World!"]
Then the following:
x = f() if f() else ""
is logically equivalent to:
x = f() or ""
Since f() is treated as a boolean expression in both cases and f() will evaluate to a True(ish) or False(ly) value both expressions will return the same result.
This is called Logical Equivalence
In logic, statements p and q are logically equivalent if they have the
same logical content. This is a semantic concept; two statements are
equivalent if they have the same truth value in every model (Mendelson
1979:56). The logical equivalence of p and q is sometimes expressed as
p \equiv q, Epq, or p \Leftrightarrow q. However, these symbols are
also used for material equivalence; the proper interpretation depends
on the context. Logical equivalence is different from material
equivalence, although the two concepts are closely related.
They will have the same result, since both treat self.getData()'s result in a boolean context, but beware:
1)
return self.getData() if self.getData() else ''
will run the function getData twice, while
2)
return self.getData() or ''
will only run it once. This can be important if getData() takes a while to execute, and it means that 1) is not the same as 2) if the function getData() has any side effects.
Stick with 2).
The only difference I see is that the first one will call self.getData() twice, with the first one being used to evaluate boolean value and the second may be returned(if the first evaluated to True).
The other option will evaluate the function only once, using it both as boolean checking and returning.
This can be crucial if, for example, self.getData() deletes or modifies the data after returning it or the function takes long to compute.
Situation
(Note: The following situation is just exemplary. This question applys to anything that can evaluate to bool)
A default list should be used if the user does not provide a custom list:
default_list = ...
custom_list = ...
if custom_list:
list = custom_list
else:
list = default_list
You can shorten this to:
default_list = ...
custom_list = ...
list = custom_list if custom_list else default_list
Now, as per https://docs.python.org/2.7/reference/expressions.html#or ...
The expression x or y first evaluates x; if x is true, its value is returned; otherwise, y is evaluated and the resulting value is returned.
..., or does not return a boolean, but rather the first value whose boolean conversion is not false. Therefore, the following would be valid code:
list = custom_list or default_list
This is similar to the C# Null Coalescing Operator, except it should be recoined in Python as False Coalescing Operator, which returns the first non-false argument.
Question
The last example seems to be easier to read, but is it considered pythonic?
Neither pep8 (the program) nor pylint do complain.
That is perfectly valid and you can use that. Even the documentation of or has an example for the same.
Note that neither and nor or restrict the value and type they return to False and True, but rather return the last evaluated argument. This is sometimes useful, e.g., if s is a string that should be replaced by a default value if it is empty, the expression s or 'foo' yields the desired value.
However, the or method has a limitation. If you want to purposefully allow a Non-Truthy value, then it is not possible with that.
Let us say you want to allow an empty list
my_list = [] or default_list
will always give default_list. For example,
print [] or [1, 2, 3]
# [1, 2, 3]
But with conditional expression we can handle it like this
custom_list if isinstance(custom_list, list) else default_list
Dusting off the older documents, quoting the BDFL's FAQ,
4.16. Q. Is there an equivalent of C's "?:" ternary operator?
A. Not directly. In many cases you can mimic a?b:c with a and b or
c, but there's a flaw: if b is zero (or empty, or None -- anything
that tests false) then c will be selected instead. In many cases you
can prove by looking at the code that this can't happen (e.g. because
b is a constant or has a type that can never be false), but in general
this can be a problem.
Steve Majewski (or was it Tim Peters?) suggested the following
solution: (a and [b] or [c])[0]. Because [b] is a singleton list it
is never false, so the wrong path is never taken; then applying [0] to
the whole thing gets the b or c that you really wanted. Ugly, but it
gets you there in the rare cases where it is really inconvenient to
rewrite your code using 'if'.
Yes, using or for it's short-circuiting properties was the norm, before the conditional expression construct was added to the language.
It was, and still is, perfectly pythonic to use:
foo = bar or baz
to fall back to a default if bar is false-y (evaluates to false in a boolean context). The fact that it short-circuits also lets you do things like:
foo = bar or expensive_calculation(baz) # only if bar is false-y
and not have expensive_calculation() execute if bar is truth-y (evaluates to true in a boolean context). Similarly, you can use and to ensure that preconditions are met:
foo = bar and bar(baz) # call `bar()` only if it is truth-y
You should use a conditional expression for:
foo = bar and spam or eggs
however. That's what the conditional expression aims to replace. The idea was that if bar is truth-y, then spam is picked, else eggs is picked. But that breaks down if spam is false-y! This was a common source of errors, while
foo = spam if bar else eggs
always picks spam if bar is truth-y.
I'm new to Python and while trying Python logical statements.I came across this which I'm not able to understand.Can anyone tell me whats happening here in Python 2.7.Whats the difference between 0 and False value in Python.
>>> 0 or False
False
>>> False or 0
0
Why the interpreter is giving different answers ?
You are being confused by the behaviour of the or operator; it returns the first expression that only if it is a true value; neither 0 nor False is true so the second value is returned:
>>> 0 or 'bar'
'bar'
>>> False or 'foo'
'foo'
Any value that is not numerical 0, an empty container, None or False is considered true (custom classes can alter that by implementing a __bool__ method (python 3), __nonzero__ (python 2) or __len__ (length 0 is empty).
The second expression is not even evaluated if the first is True:
>>> True or 1 / 0
True
The 1 / 0 expression would raise a ZeroDivision exception, but is not even evaluated by Python.
This is documented in the boolean operators documentation:
The expression x or y first evaluates x; if x is true, its value is returned; otherwise, y is evaluated and the resulting value is returned.
Similarly, and returns the first expression if it is False, otherwise the second expression is returned.
The nature of this behavior is in python's order of expression evaluation. Python evaluates expressions from left to right, and it does it in a lazy manner. This means, that ones interpreter reaches the point, when the value of the expression is True, regardless of the rest of the expression, it will follow the branch of workflow, associated with the expression. If none of the expressions is True, it will simply return the most recent (last one). This gives the benefits of saving computational resources. Consider the following code:
>>>False or False or True or range(10**8)
True
>>>
Note, that range(10**8) is never called in this case, hence, a lot of time is saved.
This question already has answers here:
Why do these list methods (append, sort, extend, remove, clear, reverse) return None rather than the resulting list?
(6 answers)
Closed 4 years ago.
Is there a reason being list.append evaluating to false? Or is it just the C convention of returning 0 when successful that comes into play?
>>> u = []
>>> not u.append(6)
True
Most Python methods that mutate a container in-place return None -- an application of the principle of Command-query separation. (Python's always reasonably pragmatic about things, so a few mutators do return a usable value when getting it otherwise would be expensive or a mess -- the pop method is a good example of this pragmatism -- but those are definitely the exception, not the rule, and there's no reason to make append an exception).
None evaluates to False and in python a function that does not return anything is assumed to have returned None.
If you type:
>> print u.append(6)
None
Tadaaam :)
because .append method returns None, therefore not None evaluates to True. Python on error usually raises an error:
>>> a = ()
>>> a.append(5)
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
a.append(5)
AttributeError: 'tuple' object has no attribute 'append'
It modifies the list in-place, and returns None. None evaluates to false.
Actually, it returns None
>>> print u.append(6)
None
>>> print not None
True
>>>
Method append modifies the list in-place and the return value None
In your case, you are creating an array — [6] — on the fly, then discarding it. The variable b ends up with the return value of None.
Why?
This comply with the principle of Command–query separation devised by Bertrand Meyer.
It states that every method should either be a command that performs an action, or a query that returns data to the caller, but not both.
In your example:
u.append(6)
append modified the state of [], so it’s not a best practice to return a value compliance with the principle.
In theoretical terms, this establishes a measure of sanity, whereby one can reason about a program's state without simultaneously modifying that state.
CQS is well-suited to the object-oriented methodology such as python.
The list.append function returns None. It just adds the value to the list you are calling the method from.
Here is something that'll make things clearer:
>>> u = []
>>> not u
False
>>> print(u.append(6)) # u.append(6) == None
None
>>> not u.append(6) # not None == True
True