Can someone explain to me why when evaluating numerical expressions Python as a result of evaluation returns the last thing that was evaluated?
For example:
3 and 5
evaluates to
5
Another question I have is why is it even evaluating these expressions, when I try to check:
3 == True
I get False but when I evaluate:
3 and 5
and get 5 as a result it obviously( I think) thinks that 3 evaluates to True since it wouldn't continue evaluating if it thought otherwise( I might be wrong here).
In contrast when I evaluate:
0 and 3
I get 0, what I think is happening is that Python checks whether 0 is True, decides it's not and spits it out.
I'm sorry if it all sounds a bit chaotic but I stumbled across this in my book and was curious if there is something I'm missing.
Yes, in python any value is either truthy or falsy. Every integer is truthy except for 0. With the boolean operators or and and, python returns the last expression it evaluates, for example 3 or 5 will return 3 as python first sees that 3 is truthy and does not have to evaluate 5 and returns 3.
In 0 and 5, 0 is falsy and so python does not evaluate the next expression and returns 0.
The reason 5 == True gives False as 5 does not equal true, it just acts truthy in boolean expressions. bool(5) == True gives True as this explicitly converts the integer to a boolean.
From the Python Reference:
The expression x and y first evaluates x; if x is false, its value is returned;
otherwise, y is evaluated and the resulting value is returned.
If you had said
0 and 5
the value of the first thing evaluated (0) would have been returned.
For the second question, 3 obviously evaluates to true when treated as a boolean, but the == operator does not coerce its arguments to boolean prior to comparison.
How boolean operations work
See documentation on boolean operations. They work in the following way:
a or b returns the first element that is evaluated as True, so in case of 0 or 3 it will be 3, and in case of 3 or 5 it will be 3 also,
a and b returns the first element evaluated as False, otherwise (in case all the elements are evaluated as True) the last element is returned, so 0 and 3 will became 0 and 3 and 5 will became 5,
Solution
But there is a solution to your problem. Just cast the result into boolean using bool():
>>> bool(0 or 3)
True
>>> bool(3 or 5)
True
>>> bool(0 and 3)
False
>>> bool(3 and 5)
True
Did it help?
EDIT:
Another solution
Actually I think in your case there may be even a better solution to your problem. See this:
bool(a or b) can be replaced by any([a, b]), and
bool(a and b) can be replaced by all([a, b]),
and I now believe this is a more reasonable solution.
Related
I've been tinkering a little with Python operators and came across something I'm not sure about.
If I perform a bitwise operation (&, |) on 2 integers I will get unsurprisingly their bitwise value.
Meaning:
>>> a = 11
>>> b = 3
>>> a & b
3
This is because it performs bitwise AND on the binary representation of these numbers.
However, if I use the built in and operator I will get the second variable, irrespective of its type:
>>> b and a
11
>>> 'b' and 'a'
'a'
Why is it so?
Logical operators operate on the truthiness of an object. Every object has truth value, unless it has a __bool__ method that is explicitly overridden to raise an error. The major difference between a and b (logical) and a & b (bitwise) is that the former apply to any objects, while the latter only apply to numeric types that support bitwise operations1.
Python's logical operators are specifically designed to return the result of the last object evaluated:
a and b: Returns a Falsy a, or b (if a is truthy)
a or b: Returns a Truthy a, or b (if a if falsy)
From the tutorial:
The Boolean operators and and or are so-called short-circuit operators: their arguments are evaluated from left to right, and evaluation stops as soon as the outcome is determined. For example, if A and C are true but B is false, A and B and C does not evaluate the expression C. When used as a general value and not as a Boolean, the return value of a short-circuit operator is the last evaluated argument.
This property is used semi-idiomatically to check values before accessing them. For example, if a list must contain an element, you can do something like
if x and x[0] == value:
# ...
This will not raise an error, because if x is Falsy (empty), the and expression will return x instead of x[0] == value.
1 Set-like objects also support & as the intersection operator. This is conceptually similar to what the bitwise operator does for integers (you can think of bits as sets), and in no way detracts from the rest of the answer.
The documentation says:
The expression x and y first evaluates x; if x is false, its value is returned; otherwise, y is evaluated and the resulting value is returned.
Since Python considers the boolean value for both strings and non-zero integers to be True, x and y would imply True and True, and since the boolean of the first statement is not False, the second statement is evaluated and the resulting value (which is the value of the second term) is returned.
The first case with and:
>>> b and a #(11 and 3, both the values evaluates to be true because non-zero)
11
>>> 'b' and 'a' #(again both are evaluated to be true because non-empty)
For and all the conditions need to be True, so checked upto the last item if the previous evaluates to be True, hence you get the last item.
Case 1 : A and B
here consider A ,B both are non zeroes for and it checks both A,B that is it first evaluates A if in A after conversion in binary(for understanding consider positive integers , A > 0 and B > 0) whether 1 is present or not , if yes it moves to B and returns B as output. Because and checks both A and B.
A or B
here it checks the A as same as above if it has 1 after converting in to binary,
if A is True it return A (obviously A > 0 so it return A only ).
case 2 : suppose Any 1 in A,B or both A,B are ZEROES
I will try to explain in better way . I hope we all know truth tables for 'AND' and 'OR' and 'XOR'.
Same thing happening here just replace 1's and 0's with any number, if you want you use only 1's and 0's to understand in better way.
In python why this statement is giving false:- print(3 < (2 or 10))
Shouldn't it give true?
Please explain
(2 or 10) is 2 as evaluation stops (shortcuts) as soon as the result is clear. And 3 < 2 is false.
Playing around with it in the shell might already make it clear what is happening:
>>> 3 < (2 or 10)
False
>>> (2 or 10)
2
>>> (0 or 10)
10
>>> (1 or 10)
1
Of course, if (2 or 10) is equal to 2, then 3 is not smaller.
See also 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.
Integers are usually True, except for 0 and None. That can be found here:
In the context of Boolean operations, and also when expressions are used by control flow statements, the following values are interpreted as false: False, None, numeric zero of all types, and empty strings and containers (including strings, tuples, lists, dictionaries, sets and frozensets). All other values are interpreted as true. User-defined objects can customize their truth value by providing a __bool__() method.
print(2 or 10) prints 2
print(10 or 2) prints 10
Therefore, print(3 < (2 or 10)) means print(3 < 2) which is False
Python always iterate from left --> right so when program see that there is first value is something and then there is or statement then it stops iterating and take the value which was first. In Your case it itrate first 2 or 10 and take 2 and 3 is greater than 2 . So here your statement is false.
This question already has answers here:
How do Python's any and all functions work?
(10 answers)
Closed 2 years ago.
I'm trying to write a script that simulates a system of chemical reactions over time. One of the inputs to the function is the following array:
popul_num = np.array([200, 100, 0, 0])
Which contains the number of discrete molecules of each species in the system. Part of the main function has an if statement that's meant to check that number of molecules is positive. if it is processed to the next iteration, else break out of the whole simulation
if popul_num.any() < 0: # Any method isn't working! --> Does .any() work on arrays or just lists?
print("Break out of loop negative molecule numbers")
tao_all = tao_all[0:-1]
popul_num_all = popul_num_all[0:-1]
else:
break
I've used the .any() to try find if any element of the popul_num array is negative. But it doesn't work, it doesn't throw an error, the system just never enters the if statement and I can't figure out why?
I've just ran the program and the final number of molecules the system returned was: [135 -19 65 54] the program should have broken out before the second element got to -19.
Any suggestions?
Cheers
You should use .any() on a boolean array after doing the comparison, not on the values of popul_num themselves. It will return True if any of the values of the boolean array are True, otherwise False.
In fact, .any() tests for any "truthy" values, which for integers means non-zero values, so it will work on an array of integers to test if any of them are non-zero, which is what you are doing, but this is not testing the thing that you are interested in knowing. The code then compounds the problem by doing an < 0 test on the boolean value returned by any, which always evaluates True because boolean values are treated as 0 and 1 (for False and True respectively) in operations involving integers.
You can do:
if (popul_num < 0).any():
do_whatever
Here popul_num < 0 is a boolean array containing the results of element-by-element comparisons. In your example:
>>> popul_num < 0
array([False, False, False, False], dtype=bool)
You are, however, correct to use array.any() (or np.any(array)) rather than using the builtin any(). The latter happens to work for a 1-d array, but would not work with more dimensions. This is because iterating e.g. over a 4d array (which is what the builtin any() would do) gives a sequence of 3d arrays, not the individual elements.
There is also similarly .all(). The above test is equivalent to:
if not (popul_num >= 0).all():
The any method of numpy arrays returns a boolean value, so when you write:
if popul_num.any() < 0:
popul_num.any() will be either True (=1) or False (=0) so it will never be less than zero. Thus, you will never enter this if-statement.
What any() does is evaluate each element of the array as a boolean and return whether any of them are truthy. For example:
>>> np.array([0.0]).any()
False
>>> np.array([1.0]).any()
True
>>> np.array([0.0, 0.35]).any()
True
As you can see, Python/numpy considers 0 to be falsy and all other numbers to be truthy. So calling any on an array of numbers tells us whether any number in the array is nonzero. But you want to know whether any number is negative, so we have to transfrom the array first. Let's introduce a negative number into your array to demonstrate.
>>> popul_num = np.array([200, 100, 0, -1])
>>> popul_num < 0 # Test is applied to all elements in the array
np.ndarray([False, False, False, True])
>>> (popul_num < 0).any()
True
You asked about any on lists versus arrays. Python's builtin list has no any method:
>>> [].any()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'any'
There is a builtin function (not method since it doesn't belong to a class) called any that serves the same purpose as the numpy .any method. These two expressions are logically equivalent:
any(popul_num < 0)
(popul_num < 0).any()
We would generally expect the second one to be faster since numpy is implemented in C. However only the first one will work with non-numpy types such as list and set.
any() is a method for use on iterables. It returns True if any of the items in the iterable are truthy. You want something more like:
if any([True for x in popul_num if x > 0]):
print("at least one element was greater than zero!")
any() returns True, if at least one of the elements is True:
L1 = [False, False, False]
any(L1)
# >>> False
L1 = [True, False, False]
any(L1)
# >>> True
L1 = ["Hi", False, False]
any(L1)
# >>> True
L1 = []
any(L1)
# >>> False
any() returns True if at least one element in a NumPy array evaluates to True and np.all test whether all array elements along a given axis evaluate to True. What you need to solve your problem is the all method.
I want to write this if statement as compact as possible (to avoid having duplicate code)
if length == 10 if boolean is False or length == 13 if boolean is True:
The part that PyCharm does not like is the
if boolean is True
It asks for a colon.
PyCharm does not allow me to run it. Does anyone have a nice compact solution to this if?
I think you meant
if (not boolean and length == 10) or (boolean and length == 13):
The parentheses aren't necessary, but I think they help readability. #jonsharpe's solution is even shorter and only has to evaluate boolean once, but it may be harder to read, especially if you're not familiar with Python's ternary expressions.
Never use is for equality comparison (that's what == is for), but boolean types should never be explicitly compared to True or False anyway.
You can use a conditional expression (also known as a "ternary") to write it out much more concisely:
if length == 13 if boolean else length == 10:
or, equivalently:
if length == (13 if boolean else 10):
Per the documentation:
The expression x if C else y first evaluates the condition, C (not x); if C is true, x is evaluated and its value is returned; otherwise, y is evaluated and its value is returned.
I am confused as to when I should use Boolean vs bitwise operators
and vs &
or vs |
Could someone enlighten me as to when do i use each and when will using one over the other affect my results?
Here are a couple of guidelines:
Boolean operators are usually used on boolean values but bitwise operators are usually used on integer values.
Boolean operators are short-circuiting but bitwise operators are not short-circuiting.
The short-circuiting behaviour is useful in expressions like this:
if x is not None and x.foo == 42:
# ...
This would not work correctly with the bitwise & operator because both sides would always be evaluated, giving AttributeError: 'NoneType' object has no attribute 'foo'. When you use the boolean andoperator the second expression is not evaluated when the first is False. Similarly or does not evaluate the second argument if the first is True.
Here's a further difference, which had me puzzled for a while just now: because & (and other bitwise operators) have a higher precedence than and (and other boolean operators) the following expressions evaluate to different values:
0 < 1 & 0 < 2
versus
0 < 1 and 0 < 2
To wit, the first yields False as it is equivalent to 0 < (1 & 0) < 2, hence 0 < 0 < 2, hence 0 < 0 and 0 < 2.
In theory, and and or come straight from boolean logic (and therefore operate on two booleans to produce a boolean), while & and | apply the boolean and/or to the individual bits of integers. There are a lot lot of questions here on how the latter work exactly.
Here are practical differences that potentially affect your results:
and and or short-circuiting, e.g. True or sys.exit(1) will not exit, because for a certain value of the first operand (True or ..., False and ...), the second one wouldn't change the result so does not need to be evaluated. But | and & don't short-circuit - True | sys.exit(1) throws you outta the REPL.
& and | are regular operators and can be overloaded, while and and or are forged into the language (although the special method for coercion to boolean may have side effects).
This also applies to some other languages with operator overloading
and and or return the value of an operand instead of True or False. This doesn't change the meaning of boolean expressions in conditions - 1 or True is 1, but 1 is true, too. But it was once used to emulate a conditional operator (cond ? true_val : false_val in C syntax, true_val if cond else false_val in Python). For & and |, the result type depends on how the operands overload the respective special methods (True & False is False, 99 & 7 is 3, for sets it's unions/intersection...).
This also applies to some other languages like Ruby, Perl and Javascript
But even when e.g. a_boolean & another_boolean would work identically, the right solution is using and - simply because and and or are associated with boolean expression and condition while & and | stand for bit twiddling.
If you are trying to do element-wise boolean operations in numpy, the answer is somewhat different. You can use & and | for element-wise boolean operations, but and and or will return value error.
To be on the safe side, you can use the numpy logic functions.
np.array([True, False, True]) | np.array([True, False, False])
# array([ True, False, True], dtype=bool)
np.array([True, False, True]) or np.array([True, False, False])
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
np.logical_or(np.array([True, False, True]), np.array([True, False, False]))
# array([ True, False, True], dtype=bool)
The hint is in the name:
Boolean operators are for performing logical operations (truth testing common in programming and formal logic)
Bitwise operators are for "bit-twiddling" (low level manipulation of bits in byte and numeric data types)
While it is possible and indeed sometimes desirable (typically for efficiency reasons) to perform logical operations with bitwise operators, you should generally avoid them for such purposes to prevent subtle bugs and unwanted side effects.
If you need to manipulate bits, then the bitwise operators are purpose built. The fun book: Hackers Delight contains some cool and genuinely useful examples of what can be achieved with bit-twiddling.
The general rule is to use the appropriate operator for the existing operands. Use boolean (logical) operators with boolean operands, and bitwise operators with (wider) integral operands (note: False is equivalent to 0, and True to 1). The only "tricky" scenario is applying boolean operators to non boolean operands. Let's take a simple example, as described in [SO]: Python - Differences between 'and' and '&': 5 & 7 vs. 5 and 7.
For the bitwise and (&), things are pretty straightforward:
5 = 0b101
7 = 0b111
-----------------
5 & 7 = 0b101 = 5
For the logical and, here's what [Python.Docs]: Boolean operations states (emphasis is mine):
(Note that neither and nor or restrict the value and type they return to False and True, but rather return the last evaluated argument.
Example:
>>> 5 and 7
7
>>> 7 and 5
5
Of course, the same applies for | vs. or.
Boolean operation are logical operations.
Bitwise operations are operations on binary bits.
Bitwise operations:
>>> k = 1
>>> z = 3
>>> k & z
1
>>> k | z
3
The operations:
AND &: 1 if both bits are 1, otherwise 0
OR |: 1 if either bit is 1, otherwise 0
XOR ^: 1 if the bits are different, 0 if they're the same
NOT ~': Flip each bit
Some of the uses of bitwise operations:
Setting and Clearing Bits
Boolean operations:
>>> k = True
>>> z = False
>>> k & z # and
False
>>> k | z # or
True
>>>
Boolean 'and' vs. Bitwise '&':
Pseudo-code/Python helped me understand the difference between these:
def boolAnd(A, B):
# boolean 'and' returns either A or B
if A == False:
return A
else:
return B
def bitwiseAnd(A , B):
# binary representation (e.g. 9 is '1001', 1 is '0001', etc.)
binA = binary(A)
binB = binary(B)
# perform boolean 'and' on each pair of binaries in (A, B)
# then return the result:
# equivalent to: return ''.join([x*y for (x,y) in zip(binA, binB)])
# assuming binA and binB are the same length
result = []
for i in range(len(binA)):
compar = boolAnd(binA[i], binB[i])
result.append(compar)
# we want to return a string of 1s and 0s, not a list
return ''.join(result)
Logical Operations
are usually used for conditional statements. For example:
if a==2 and b>10:
# Do something ...
It means if both conditions (a==2 and b>10) are true at the same time then the conditional statement body can be executed.
Bitwise Operations
are used for data manipulation and extraction. For example, if you want to extract the four LSB (Least Significant Bits) of an integer, you can do this:
p & 0xF