What does the following line accomplish? [duplicate] - python

This question already has answers here:
How do "and" and "or" act with non-boolean values?
(8 answers)
Closed 2 years ago.
So I was trying to solve an algorithm and while trying to find other solutions to it, I found one which was very short and very fast, just one problem...I can't seem to understand what this line is doing:
Full solution:
def proper_fractions(n):
phi = n > 1 and n
print(phi)
for p in range(2, int(n ** .5) + 1):
if not n % p:
phi -= phi // p
while not n % p:
n //= p
if n > 1: phi -= phi // n
return phi
Line that I don't understand:
phi = n > 1 and n
Please forgive me If it is very easy to understand, I just have never come across something like this, I've only used and in if statements, here is what I changed the line to (I think it works like the other one, but not sure how the other one does exactly what the following line which I changed does):
phi = n if n > 1 else False
Please could someone clear-up how the line that I don't understand works?

As can be seen in the Python docs, Python logical operators are not necessarily "purely Boolean". In particular, and and or are not actually guaranteed to return True or False. Instead, they return one of their operands. Here's how Python defines the value of x and y:
if x is false, then x, else y
"False" in this context does not mean that x has to be the value False. Instead, it just has to be anything with a falsy value, like a zero of any type or an empty sequence or collection.
In this case, when n > 1 evaluates False, the operator short-circuits and returns n > 1, AKA False. But if n > 1 evaluates True, the operator simply returns n without modifying it in any way, as the docs describe.

The truth table for a and b looks like this:
True and True == True
True and False == False
False and True == False
False and False == False
We can observe three things:
When a is True, the result is always the same as b.
When a is False, the result is always False, in other words, it is always the same as a.
When a is False, b is completely irrelevant, so we don't even need to evaluate it.
Note that in Python, True and False are not the only objects that have a boolean value. In fact, every single object in Python has a boolean value. E.g. 0 has a falsey value, "Hello" has a truthy value, and so on.
So, with the optimizations we discovered about the truth table, and the added condition that we need to handle values other than True and False, we can construct the following, revised, truth table:
a and b == a # if `a` is *falsey*
a and b == b # if `a` is *truthy*
This matches up with the documentation of and:
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.
Similar reasoning applies to or:
a or b == b # if `a` is *falsey*
a or b == a # if `a` is *truthy*
So, the result of the line in question:
phi = n > 1 and n
will be that phi is assigned False if n <= 1 and n if n > 1.
The further computation that is performed with phi in turn works because False is equivalent to 0 in a numeric context, i.e.
False + 1 == 1
False - 1 == -1
This makes the rest of the algorithm work, which contains statements like:
phi -= phi // p
Where arithmetic is performed with the value of phi.
See the documentation on the numeric types for details, which contains the following statement [bold emphasis mine]:
There are three distinct numeric types: integers, floating point numbers, and complex numbers. In addition, Booleans are a subtype of integers.

From section 6.11 of the documentation:
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.
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. Because not has to create a new value, it returns a boolean value regardless of the type of its argument (for example, not 'foo' produces False rather than ''.)
So it first check if n > 1, if it is true, then it return s n, otherwise it returns False.

First, it's first checking if the first evaluation is True or False (Null value are considered false). Then if it's True, will return the second value. In this case, n.
More details:
> if n = 3
> 1. phi = n > 1 and n
> 2. phi = 3 > 1 and 3
> 3. phi = True and 3
> 4. phi = 3

Related

Does the 'or' operator or the equality operator have higher precedence in Python? [duplicate]

This question already has answers here:
Why does "a == x or y or z" always evaluate to True? How can I compare "a" to all of those?
(8 answers)
Closed 4 months ago.
Every precedence table I look at for Python states the equality(==) operator is evaluated before the 'or' keyword. Why then is '1' printed for this code? I thought the expression would evaluate as false, and the if block wouldn't run.
number = 1
if number == 0 or 1:
print(number)
How about the following code? Why isn't 'False' printed? Instead, the integer 1 is printed. It confuses me how the variable 'a' gets assigned as 1 instead of as a False boolean value.
number = 1
a = (number == 0 or 1)
print(a)
Well, you are correct. == does evaluate before or. In the case of if number == 1 or 1, what happens is that python evaluates numbers that aren't 0 as True. So the first "argument" (number == 1) will evaluate to False, while 1 will evaluate to True. And False or True will always be True.
The other case (a = (number == 0 or 1)) is a little more tricky. In the case of having an assignment of a variable to multiple expressions chained with or, Python will assign the variable to the first expression that evaluates to True and if it doesn't find any, it will assign to the last expression.
In this case, the first expression (number == 0) is False while 1 on the other hand is True. a therefore gets assigned the value of the second expression, which is 1.
number = 1
if number == 0 or 1:
print(number)
In above if statement, you have two conditions. It always tries to find the boolean expression of the given conditions and block will get executed only when it finds True.
number == 0
First condition evaluates False since the number is 1
boolean(1)
Second condition evaluates True which is why block of code executed and 1 is printed.
Same happened with the other part of your code.
number = 1
a = (number == 0 or 1)
print(a)
Just remember that our code tries to find the True values. Hope, it helps.
See python docs Boolean operations
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.
Going by your example:
number = 1
if number == 0 or 1:
print(number)
# disected
print(number == 0) # prints False
print(False or 1) # prints 1 as it is a truthy value
In your boolean operation the equality operator == is evaluated before the or keyword.
As number == 0 evaluates to False the right side of the or operator gets evaluated. 1 is a true statement so 1 gets returned.
But what if both sides evaluate to False or have a falsy value?
number = 1
if number == 0 or 0:
print(number) # won't print
As number == 0 evaluates to False, 0 is evaluated. That is a falsy value, so the or operation returns False, or in this case the falsy value 0 which evaluates to False in the if statement.

What does and-or clause mean under a for loop? [duplicate]

This question already has answers here:
How do "and" and "or" act with non-boolean values?
(8 answers)
Closed 1 year ago.
Recently I read several lines of Python codes and got a bit confused.
p = 'a*b.*'
lp = len(p)
m = [0]*(lp+1)
for i in range(1, lp + 1):
m[i] = m[i-1] and p[i-1] == '*' or (i > 1 and m[i-2] and p[i-1] == '*')
print(m)
The result printed out as [0, False, 0, False, 0, False]
p is a string, and lp is the length of string p. I created a list m [0, 0, 0, 0, 0, 0]. Then I am getting confused:
I loop all the elements in this array(list). What does "and" and "or" mean here in the loop. Double equal signs are also used here. I thought "and" and "or" can only be used under if-else clauses. What does this mean here? Could anyone please translate for me? Thanks!
and and or are actually boolean operators and they can be used anywhere to compare two values.
According to the docs,
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.
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.
Note also that
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.
So, in your case, the values being compared are
m[i-1] type int, evaluates to False if it's 0 else True
p[i-1] == '*' type bool, evaluates to False if p[i-1] is not equal to '*' else True
i > 1 type bool, evalueates to False if i is less or equal to 1 else True
m[i-2] type int, evaluates to False if it's 0 else True
So why the snippet outputs [0, False, 0, False, 0, False]? If you debug this program, you'll notice that in some iterations, the value at the left of the first and is returned. In these iterations, the result will be a integer (0) since m[i-1] is a integer. In other iterations, the value at the right of the first and is returned. In these, the result will be a boolean.

Booleans with numbers in Python

I came across this implementation of gcd in Python:
def gcd(x,y): return y and gcd(y, x % y) or x
What I don't understand is how the boolean is working in the return? After trying some numbers in the interpreter I noticed that and always returns the number on the right, while or returns the number on the left. Why is this? Also, can you walk me step by step through a simple call of this function so I can understand what is happening?
This is because of how and and or operators evaluate in Python.
From documentation -
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.
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.
They do not return True or False , they return the last evaluated value , and that is why we can write things like -
s = s or "Some default value"
To default the value of s if its None or empty string or empty list, or 0.
Basically, or returns the first non false-like value ( where false-like values are 0, or None or Empty string/list/tuple, etc ) Or the last false-like value if all the values are false-like. Example -
In [1]: 0 or 10
Out[1]: 10
In [2]: 5 or 0 or 10
Out[2]: 5
In [7]: 0 or '' or [] or ()
Out[7]: ()
And, and returns the first false-like value, or the last true-like value , if all the values are true-like. Example -
In [3]: 0 and 10
Out[3]: 0
In [4]: 5 and 10
Out[4]: 10
In [6]: 5 and 0 and 10
Out[6]: 0
In your case, it works as -
if y is 0 it returns x (irrespective of the value of x) .
otherwise it computes gcd(y, x%y) if that is non-zero returns it. (Though it would never really be 0)
if the result of gcd(y, x%y) is 0, then it returns x .
This is called "short circuiting." Whenever Python knows what the result of a boolean expression is going to be, it stops evaluating. This is an optimization, but it also makes for some handy idioms, like assigning default values.
def do_a_thing(maybelist=None):
# this is done all the time when you want the default argument to be
# a list, but you don't want to make the mistake of a mutable default argument
maybelist = maybelist or []
The implementation example you gave is confusing to someone who doesn't know about Euclid's Algorithm for calculating gcd's, because it's not obvious how the heck it actually calculates the gcd. I would say that that is an example of someone abusing short circuit evaluation.
In Python, the only integer that defaults to False is zero. Logical values perform short-circuiting, as one of the comments say.
With the statement:
a and b
If 'a' evaluates to False, then 'b' does not need to be evaluated, so the result of the expression is 'a', but if 'a' evaluates to True, then b still needs to be evaluated, so b will be the result of the expression unless a evaluates to False.
`or' works the other way around, which makes sense if you think about it.
and and or are not strictly Boolean operators in Python. x and y and x or y will always evaluate to either x or y, depending on the "truthiness" of the value. False values are numerical zeros, empty strings, and empty containers; all other values are true. This means that
x and y == x if x is false; y is not evaluated
x and y == y if x is true
x or y == x if x is true; y is not evaluated
x or y == y if x is false
The only time either evaluates to an actual Boolean value is when the x or y value involved is an actual Boolean value.

Trying to understand a simple feature about 'and' command in python. Can anyone clarify it? [duplicate]

This question already has answers here:
and / or operators return value [duplicate]
(4 answers)
What does "variable or 0" mean in python?
(4 answers)
Closed 7 years ago.
In Python, if I write
z = 1 and 2
print z
Then it yields "2".
But if I write
z = 0 and 2
print z
Now, it yields "0".
It may not be much important in real life problem, but I'm trying to understand the logic here.
0, [], "" are all false-ish (they are treated as False in a python condition). and returns the first false-ish value or the last one. This is called short-circuit evaluation. That's why in one case it returns 2 (the last) and in the other it returns 0 (the false-ish).
In fact if you think about the logic operation, you can short-circuit this behaviour:
x and y (with x false-ish) -> x
x and y (with x true-ish) -> y
When plugged into a condition it will evaluate as:
In the first case it evaluates the boolean result of x which is False. This is the correct result for the and operation, since False and y = False for any y.
In the second case it evaluates the boolean value of y. Since x is True, the result of and should be False when y is False and True when y is True (it reflects the value of y).
c = a and b
is the same as
if a:
c=b
else:
c=a
I think more interesting is or:
c = a or b
is the same as
if a:
c=a
else:
c=b
Note also that if a: is a short way of if bool(a):. bool returns False for this objects/values:
None, 0, False, "", [], tuple(), dict(), set()
As you can see, they are all somehow empty...
The and operator in python short circuits. That is: it only evaluates enough operands (from left to right) as are necessary to determine whether the outcome is True or False. The result of and is False so in the second case, where 0 evaluates to False, and returns 0, but as 1 is True, the second operand must also be evaluated and returned.
0 is treated as False and anything above zero is treated as True so z = 1 and 2 sets z equal to 2 and z = 0 and 2 is 0 because it evaluates to False.

Python: what is the operation that returns 6 for the expression (2 and 2*3)?

My first question is what is the more abstract question for the question: 'what is the operation that returns 6 for the expression (2 and 2*3)? Please feel free to retitle my question appropriately.
My second question is what is it that is going on in python that returns 6 for (2 and 2*3). There seems something elegant going on here, and I'd like to read up on this operation.
From the Python language reference:
Note that neither and nor or restrict the value and type they return to False and True, but rather return the last evaluated argument.
As such, 2 and 2*3 means it first evaluates bool(2), which evaluates to True, and then it evaluates bool(2*3) which evaluates to True. Therefore it'll return the last evaluated argument, which is 2*3 (6).
According to the python docs
x and y : if x is false, then x, else y
First you have to read this and then you have to read this. :)
After that you will know that and is a boolean operator, that tries to convert it's first operand to boolean. So if you read the first thing you will see that 2 is converted to True.
The third thing you need to know is that the and operand will return it's first argument if it is converted to False and it's second argument if it evaluates to True.
So basically
z = x and y
Can be translated to:
if x:
z = y
else:
z = x
And now you understand everything. :)
2 is evaluated to True and then and operator returns the value of it's second argument which is 6.
Applying lazy evaluation, python return for a and b a if a evaluates to False and b if a evaluates to True.
Hence 2 evaluates to True, 2 and 2*3 return 2*3 which equals 6.
Basically it's same as 2 and 6.
How it works? and returns first element if it's considered False (False, 0, [] ...) and return second otherwise
This is to do with how Python evaluates the expression x and y. It returns y if x is True, and x if x if False.
So, in case of 2 and 2 * 3, since 2 is evaluated to True, it would return the value 2 * 3, which is 6.
In case of and operation between multiple operands, it returns the 1st non-True value, and if all the values are True, it returns the last value.
Similarly, for or operator, the expression say, A or B or C, returns the 1st True value. And if all the values are False, it returns the last value.

Categories

Resources