Python 3 order of testing undetermined - python

string='a'
p=0
while (p <len(string)) & (string[p]!='c') :
p +=1
print ('the end but the process already died ')
while (p <1) & (string[p]!='c') :
IndexError: string index out of range
I want to test a condition up to the end of a string (example string length=1)
why are both parts of the and executed is the condition is already false!
as long as p < len(string). the second part does not even need executing.
if it does a lot of performance can be lost

You're not using proper boolean and. Use it and you won't see this problem. What you're using (&) is a bitwise comparison, which evaluates both sides.

Bitwise AND, "a & b", should be thought of as
function _bitwise_and(A,B):
# A and B are Python expressions
# which result in lists of 1's and 0's
a = A.evaluate()
b = B.evaluate()
return [ 1 if abit==1 and bbit==1 else 0 for abit,bbit in zip(a,b)]
so, graphically,
a: ... 0 1 1 0
b: ... 1 0 1 0
--------
a&b ... 0 0 1 0 <- each bit is 1 if-and-only-if the
corresponding input bits are both 1
and the result is a list of bits, packed into an integer.
.
Logical AND, "a and b", should instead be thought of as
function _and(A,B):
# A and B are Python expressions which result in values having truthiness
a = A.evaluate()
if is_truthy(a):
b = B.evaluate()
return b
else:
return a
.
Notice: if the result of A is falsy, B never gets evaluated - so if expression B has an error when evaluated, bitwise AND will result in an error while logical AND will not.
This is the basis for the common Python idiom,
while (offset in data) and test(data[offset]):
do_something_to(data[offset])
next offset
... because data[offset] is only evaluated if offset is a useable (non-error-producing) value.
By using '&' instead of 'and', you guarantee an error by evaluating data[last_offset+1] at the end of your loop.
.
Of course, this could have been avoided with another common idiom:
for ch in string if ch=='c':
do_something_to(ch)
which avoids IndexError problems altogether.

You need to use the boolean operators and and or rather than the bitwise operators & and |

Related

Why is the "1" after sum necessary to avoid a syntax error

Why does this work:
def hamming_distance(dna_1,dna_2):
hamming_distance = sum(1 for a, b in zip(dna_1, dna_2) if a != b)
return hamming_distance
As opposed to this:
def hamming_distance(dna_1,dna_2):
hamming_distance = sum(for a, b in zip(dna_1, dna_2) if a != b)
return hamming_distance
I get this error:
Input In [90]
hamming_distance = sum(for a, b in zip(dna_1, dna_2) if a != b)
^
SyntaxError: invalid syntax
I expected the function to work without the 1 after the ()
The working expression can be unrolled into something like this:
hamming_distance = 0
for a, b in zip(dna_1, dna_2):
if a != b:
hamming_distance += 1
Without a number after +=, what should Python add? It doesn't know, and neither do we.
If this "unrolled" syntax or your code's relationship to it is new to you, probably start by reading up on list comprehensions, which generalize into generator expressions (which is what you have).
You wrote a generator expression. Generator expressions must produce a value (some expression to the left of the first for). Without it, you're saying "please sum all the lack-of-values not-produced by this generator expression".
Ask yourself:
What does a genexpr that produces nothing even mean?
What is sum summing when it's being passed a series of absolute nothing?
You could write a shorter genexpr with the same effect with:
hamming_distance = sum(a != b for a, b in zip(dna_1, dna_2))
since bools have integer values of 1 (for True) and 0 (for False), so it would still work, but it would be slower than sum(1 for a, b in zip(dna_1, dna_2) if a != b) (which produces fewer values for sum to work on and, at least on some versions of Python, allows sum to operate faster, since it has a fast path for summing small exact int types that bool breaks).

Is β€œAn expression that has one of two values, depending on a condition.” an accurate definition of conditional expression?

In Think Python, 2nd Edition, the author defines conditional expression as "An expression that has one of two values, depending on a condition." But after I had reflected about it, I have thought that the accuracy of the definition may be questionable. Here's a function which is written using a conditional expression:
def get_sign(n):
"""Returns 1 if n is a positive number, -1 if n is a negative number,
or 0 if n is a zero
"""
return 1 if n > 0 else -1 if n < 0 else 0
Here the conditional expression is 1 if n > 0 else -1 if n < 0 else 0. And there are two observations about that:
the expression has one of three possible values, namely 1, -1, or 0.
the value depends on two conditions, namely n > 0, and n < 0.
So, is the author's definition accurate, why and why not? Is "An expression whose value depends on one or more conditions, and that has one of several values (at least two)." a more accurate definition of conditional expression, why and why not?
You still have two outcomes. That one of those two outcomes is itself dependent on another conditional expression doesn't change this.
I've added parentheses here to illustrate my point:
1 if n > 0 else (-1 if n < 0 else 0)
So the outcome of that expression is one of these two options:
1
-1 if n < 0 else 0
That second expression is itself another conditional expression. The first value is also just an expression, which has a value once you've evaluated it; the only difference is that it produces a simple literal value. All of this makes no difference to the top-level conditional expression, it still only deals with two outcomes.
Note that only one of the expressions is actually evaluated. This matters if one of those expressions has side effects (alters state outside of the expression) or is 'expensive' in terms of memory or processing time. For example:
import time
def sleep10secs():
time.sleep(10)
return 'slow'
print('instant' if True else sleep10secs())
will print instant instantly, the sleep10secs() function is not called.

What does it mean that Python comparison operators chain/group left to right?

The Python documentation for operator precedence states:
Operators in the same box group left to right (except for
comparisons, including tests, which all have the same precedence and
chain from left to right β€” see section Comparisons...)
What does this mean? Specifically:
"Operators in the same box group left to right (except for
comparisons...)" -- do comparisons not group left to right?
If comparisons do not group left to right, what do they do instead? Do they "chain" as opposed to "group"?
If comparisons "chain" rather than "group", what is the difference between "chaining" and "grouping"?
What would be some examples to demonstrate that the comparison operators chain from left to right rather than from right to left?
Grouping (this is what non-comparison operators do):
a + b + c means (a + b) + c
Chaining (this is what comparison operators do):
a < b < c means (a < b) and (b < c)
Grouping left to right (this is the way things are grouped):
5 - 2 - 1 means (5 - 2) - 1 == 2
as opposed to grouping right to left (this would produce a different result):
5 - (2 - 1) == 4
Chaining left to right
Chaining is left to right, so in a < b < c, the expression a < b is evaluated before b < c, and if a < b is falsey, b < c is not evaluated.
(2 < 1 < f()) gives the value False without calling the function f, because 2 < 1 evaluates to false, so the second comparison does not need to be performed.
f() > 1 > g() calls f() in order to evaluate the first comparison, and depending on the result, it might or might not need to evaluate the second condition, which requires calling g().
NB. Each operand is evaluated at most once. So in the expression 1 < f() < 2, the function f() is only called once, and the value it gives is used in both comparisons (if necessary).
https://en.wikipedia.org/wiki/Short-circuit_evaluation
In fact, the chain behavior is not so obvious.
a == b == c
although one would expect this to be converted to
a == b and b == c
it is in fact converted into somthing similar to
b == c if a == b else False
which is a bit confusing if one tries to override the behavior of the comparison operators and chain them.

How does python evaluate this?

Can someone explain how these results are possible (python 2.6):
>>> 1<3>2
True
>>> (1<3)>2
False
>>> 1<(3>2)
False
I would think that one of the last two would match the first one, but apparently the operators in the first statement is somehow linked?!
Your first example shows comparison chaining. 1<3>2 means 1<3 and 3>2 (except each expression is evaluated only once). This applies to all comparison operators in Python.
Your second two examples force one comparison to be evaluated first, resulting in a boolean value which is then compared with the remaining integer.
In your first case 1<3>2 1 is actually lesser than 3 and 3 is greater than 2, so True.
In your second case (1<3)>2 (1<3) evaluates as True that represented as 1, so 1 is not greater than 2.
In your third case 1<(3>2), 1 is not lesser than True that represented as 1.
The last two statements compare booleans against an integer:
>>> True > 2
False
>>> 1 < True
False
The first statement is comparison chaining, which works for all boolean comparisons in Python. Note from the documentation:
Comparisons yield boolean values: True or False.
By placing parts of your expression in brackets, those parts get evaluated first and you end up with comparing integers and booleans.
As per docs,
Unlike C, all comparison operations in Python have the same priority, which is lower than that of any arithmetic, shifting or bitwise operation. Also unlike C, expressions like a < b < c have the interpretation that is conventional in mathematics:
comparison ::= or_expr ( comp_operator or_expr )*
comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "<>" | "!="
| "is" ["not"] | ["not"] "in"
Comparisons yield boolean values: True or False.
Comparisons can be chained arbitrarily, e.g., x < y <= z is equivalent to x < y and y <= z, except that y is evaluated only once (but in both cases z is not evaluated at all when x < y is found to be false).

Is there a difference between -1 and False in Python?

I have always thought that using -1 in a condition is alway the same as the writing False (boolean value). But from my code, I get different results:
Using True and False:
def count(sub, s):
count = 0
index = 0
while True:
if string.find(s, sub, index) != False:
count += 1
index = string.find(s, sub, index) + 1
else:
return count
print count('nana', 'banana')
Result: Takes to long for interpreter to respond.
Using 1 and -1:
def count(sub, s):
count = 0
index = 0
while 1:
if string.find(s, sub, index) != -1:
count += 1
index = string.find(s, sub, index) + 1
else:
return count
print count('nana', 'banana')
Result: 1
Why does using -1 and 1 give me the correct result whereas using the bool values True and False do not?
string.find doesn't return a boolean so string.find('banana', 'nana', index) will NEVER return 0 (False) regardless of the value of index.
>>> import string
>>> help(string.find)
Help on function find in module string:
find(s, *args)
find(s, sub [, start [, end]]) -> int
Return the lowest index in s where substring sub is found,
such that sub is contained within s[start,end]. Optional
arguments start and end are interpreted as in slice notation.
Return -1 on failure.
>>>
Your example simply repeats:
index = string.find('banana', 'nana', 0) + 1 # index = 3
index = string.find('banana', 'nana', 3) + 1 # index = 0
The -1 version works because it correctly interprets the return value of string.find!
False is of type bool, which is a sub-type of int, and its value is 0.
In Python, False is similar to using 0, not -1
There's a difference between equality and converting to a boolean value for truth testing, for both historical and flexibility reasons:
>>> True == 1
True
>>> True == -1
False
>>> bool(-1)
True
>>> False == 0
True
>>> bool(0)
False
>>> True == 2
False
>>> bool(2)
True
I have always thought that using -1 in a condition is alway the same as the writing False (boolean value).
1) No. It is never the same, and I can't imagine why you would have ever thought this, let alone always thought it. Unless for some reason you had only ever used if with string.find or something.
2) You shouldn't be using the string module in the first place. Quoting directly from the documentation:
DESCRIPTION
Warning: most of the code you see here isn't normally used nowadays.
Beginning with Python 1.6, many of these functions are implemented as
methods on the standard string object. They used to be implemented by
a built-in module called strop, but strop is now obsolete itself.
So instead of string.find('foobar', 'foo'), we use the .find method of the str class itself (the class that 'foobar' and 'foo' belong to); and since we have objects of that class, we can make bound method calls, thus: 'foobar'.find('foo').
3) The .find method of strings returns a number that tells you where the substring was found, if it was found. If the substring wasn't found, it returns -1. It cannot return 0 in this case, because that would mean "was found at the beginning".
4) False will compare equal to 0. It is worth noting that Python actually implements its bool type as a subclass of int.
5) No matter what language you are using, you should not compare to boolean literals. x == False or equivalent is, quite simply, not the right thing to write. It gains you nothing in terms of clarity, and creates opportunities to make mistakes.
You would never, ever say "If it is true that it is raining, I will need an umbrella" in English, even though that is grammatically correct. There is no point; it is not more polite nor more clear than the obvious "If it is raining, I will need an umbrella".
If you want to use a value as a boolean, then use it as a boolean. If you want to use the result of a comparison (i.e. "is the value equal to -1 or not?"), then perform the comparison.

Categories

Resources