Python for loop doesn't have expected results - python

I got a bit stuck with a for loop - what I can see it is doing appears correct but isn't exactly what I'm trying to accomplish with it. I've come from a C background but any advice here would be beneficial.
def deal(player_num, cards):
a = 0
z = 0
i = 0
b = 0
c = player_num
hand = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
for a in range(player_num):
hand[a] = cards[i] + cards[i+b+c]
b == b+1
i == i+1
z == z+1
return hand
So the for a in range(player_num) seems to be working (appends a++) but hand[0], hand[1], etc. gets the same hand. I guess it loops a but not the other variables, so I need to use more than 1 nested loop to get i++, b++ and c++?

b == b+1 is a logical expression (returning False every time), not an assignment. I'm guessing you want something like: b += 1

== is the equality operator in Python. = is the assignment operator.
== checks whether its left operand and its right operand are equal and return True or False accordingly. b and b+1 will never be equal to each other and either way it does not make sense to perform an operation without side-effect (like comparing two values for equality) and then do nothing with its result.
If you want to change the values of your variables, use the assignment operator = instead of ==.

Related

Chaining *= += operators

I have the following code:
aaa = np.random.rand(20, 1)
aaa *= 200
aaa -= 100
I wonder if it is possible to chain *= and -= operators on the same line. So, the loop over the array would be done only one time and I suppose a slight gain in performance results (of course for big arrays).
You cannot chain assignments in Python the way you can in C.
That is because in C an assignment is an expression: it has a value that can be assigned to a variable, or used in another expression. C got this idea from Algol, and those who come from the Pascal tradition tend to regard it as a misfeature. Because...
It is a trap for unwary novices who code if (a = b + c) when they mean if (a == b + c). Both are valid, but generally the second one is what you meant, because the first assigns the value of b + c to a and then tests the truth value of a.
Because assignments are not expressions in Python but statements, you will get a syntax error for if (a = b + c). It's just as invalid as if (return).
If you want to achieve what the C idiom does you can use an assignment expression (new in 3.8). You can explicitly code if (a := b + c) if what you really want to do is assign the value of b + c to a and then test the truth value of a (though technically I believe it actually tests the truth value of b + c; which comes to the same thing).
[And to the style martinets, yes, I do know that parens are redundant in a Python if statement.]
Doing them in one line would simply be
aaa = (aaa * 200) - 100
Though I doubt you'll see any performance difference between this version and what you wrote.

Performance difference between two if statements?

I asked myself if it makes a performance difference if I use an if statement with x conditions, or x if statements with only 1 condition each.
so for example:
if statement with 3 conditions:
if a == 0 and b == 0 and c == 0:
#do something
3 if statements with just one condition each:
if a == 0:
if b == 0:
if c == 0:
#do something
Why do I want to know this?
I have an if statement with around 30 conditions and my code gets really messi, so I thought about splitting my if-statement in half.
I think that the results of this examples will be the same, but I don't know if there would be a noticeable performance difference if a == 1. Would the program check all 3 conditions in the first example even if the first one (a is 1 not 0) is false?
With the given example, there won't be any difference in performance, even with if a == 0 and b == 0 and c == 0: it won't check b == 0 when the initial condition a == 0 itself is False. But considering the minimal lines of code & readability, if a == 0 and b == 0 and c == 0: would be the better option.
You can test the performance of your script using the timeit library. I will add an example below.
import timeit
stmt1 = 'if a == 0 and b == 0 and c == 0: pass'
stmt2 = """\
if a == 0:
if b == 0:
if c == 0:
pass
"""
setup1 = 'a, b, c = 0, 0, 0'
setup2 = 'a, b, c = 1, 0, 0'
print(f"First statement First setup execution time = {timeit.timeit(stmt=stmt1, setup=setup1, number=10**9)}")
print(f"First statement Second setup execution time = {timeit.timeit(stmt=stmt1, setup=setup2, number=10**9)}")
print(f"Second statement First setup execution time = {timeit.timeit(stmt=stmt2, setup=setup1, number=10**9)}")
print(f"Second statement Second setup execution time = {timeit.timeit(stmt=stmt2, setup=setup2, number=10**9)}")
Output:
First statement First setup execution time = 38.7665075
First statement Second setup execution time = 15.4141367
Second statement First setup execution time = 38.29726529999999
Second statement Second setup execution time = 15.527892699999995
This shows that there is negligible difference to how you format your if statement. But if the first condition is false then the rest of the conditions will not be checked and the execution of the code will run faster.
Edit:
Also after seeing wjandrea comment below I would like to add it to the answer if anyone in the future is wondering why this is. Per the python wiki you can read about short-circuiting operator behavior.
Any time difference between your two pieces of code is complete and total noise. Run your code a billion times, and the amount of time you might save between running one or the other is less than the time it took me to write these two sentences.
Seriously, if you need to be worried about the difference in time between the two pieces of code, Python is the wrong language.
Yes! I think there is an increase of productivity/performance if you can write your code in one line, since often times it can be easier to read and interpret; and even more so if you use descriptive variables.
In your code, I see some things that can be improved: There is what we call the (1) assignment operator, i.e. the equal(=) sign; and (2) The comparison operator, i.e. the "is equal to" (==) sign, "is greater than" (>), "is less than" (<), and etc.
When we define a variable, we use the assignment operator (=) sign. e.g:
a = 0
b = 0
c = 0
On the other hand, we use the comparison operator (such as the (==) symbol) when we make conditional statements. e.g:
if a == 0 and b == 0 and c == 0:
# do something
On to your second question: Would the program check all 3 conditions in the first example even if the first one (a is 1 not 0) is false?
a = 1
b = 0
c = 0
if a == 0:
if b == 0:
if c == 0:
# do something
Python will compare the conditions to your assigned variables, and if the condition turns out to be False, then there will be no ERROR, but it will also not execute the instruction that you've provided in your if-statement (meaning: it will not # do something).
I hope I had help you even a little bit.

Why do these shorthands not work with each other?

I was wondering how to take advantage of shorthand notation of if-else and += in Python of this simple expression:
I tried to set brackets everywhere and changed += to *= which didn't change the situation of course.
This works as expected:
a, b = 0, True
for i in range(123):
if b == True:
a = a + 1
Still working as expected, trying shorthand of if-else led me to:
a, b = 0, True
for i in range(123):
a = a + 1 if b == True else a
Finally the attempt to write:
a, b = 0, True
for i in range(123):
a += 1 if b == True else a:
fails and surprisingly I get pretty quickly huge integers for a
Moreover I'd really like something more shorthanded, e.g.:
a, b = 0, True
for i in range(123):
a += 1 if b
The for-loop needs to stay as it is, since in my case there are other operations that affect b.
Since noone seems to be posting, why it goes like this, here is mine - lines:
a = a + 1 if b == True else a
a += 1 if b == True else a
are seen by python as:
a = (a + 1 if b == True else a)
a += (1 if b == True else a)
This is why you get large numbers fast in second version - you will add a to a, when b is False. If you want to keep the if, then go:
a += (1 if b else 0)
Also don't compare b to True (or False), go foif b`, as it's more pythonic (it will prevent some weird mistakes, when other code will start to interact with yours).
EDIT: go for #Tomerikoo answer for even shorter code, but keep in mind, that those waters can be muddy and not everyone knows / easily follows, that adding boolean to int treats first as 1 (or 0 if False).
To closest to your proal is probably:
a, b = 0, True
for i in range(123):
a += b
Since bool is a subtype of int, no conversion is necessary.
You can do:
for i in range(123):
if b:a+=1
You can also do:
for i in range(123):
a = a + 1*b
Because booleans are ints:
>>> isinstance(True, int)
True
>>> True == 1
True
just note that
a += x if condition else y
will resolve to a += x if the condition is True; otherwise it will be a += y. this is why your numbers get big...
apart from that i suggest you use what U10-Forward's answer suggests.

Python Program how to count number of times the letter c shows up

Assignment:
Return the number of occurrences of character c in string s,
ignoring case. Use loops. Do not use the in-built string method count,
which does a similar thing. The idea is to learn to write loops. You
should ignore case when comparing a character of s with c.
My attempt:
def countletter(s, c): #BAD
count = 0
for c in s:
if c == c:
count += 1
return count
Am I on the right track? I seem to get some assertion errors when I test it in the main...
your return is at wrong place. So your function is actually returning only after one iteration.
Also you should not use the variable name c in for loop, use some different variable, as it replaces the value of c recieved from the function call with the current character being fetched by the for-loop.
def countletter(s, c): #BAD
count = 0
for x in s:
if x.lower() == c.lower():
count += 1
return count
print countletter("abcdefFf","F") #prints 3
print countletter("a","A") #prints 1
In addition to the answers above, there is a built-in method count in Python. You can use it in your project, if this function isn't a homework etc.(Oh, i saw now, it is an homework. But additional information is harmless.:) )
"baris".count("b")
returns 1
If you compare the variable c defined by for c in s: you are always going to get true. So, your comparison should look like c == 'c' (you can figure out how to do the case insensitive check) and your return is indented incorrectly
The position of the return statement is wrong. Delete the four spaces (or a tab what you've used)
Just as another example of a way to do this outside of the built-in count() method, one can use a generator expression and the sum() builtin:
>>> def countletter(s, c):
... return sum(x.lower() == c.lower() for x in s)
...
>>> countletter("abcdefFf", "F")
3
>>> countletter("a", "A")
1
What we do is produce a generator of True and Falses (True where the character matches). sum() will then give us the count, as True is 1 in Python, and False is 0:
>>> True == 1
True
>>> False == 0
True

Python: How to chain boolean tests to get False as soon as it gets the first False

After having a lot of trouble trying to reduce nested ifs (and a script that stopped working), I realized perhaps I am having the wrong idea of what and how boolean stuff works in python.
I had this (working fine but contorted):
if (not gotside):
if (j > 1):
if (j < a.shape[1] - 1):
if a[i, j+unit]:
print "only now I do stuff!"
And tried this (looking sreamlined by not working as desired):
if (not gotside) and (j > 1) and (j < a.shape[1] - 1) and a[i, j+unit]:
print "I'm well tested but not so indented..."
Then I tried to use "or" instead of "and", but didn' work, because (later I found) when you use x and y or even x or y you get one of x, y, and not one of True, False, acording to docs.
So, I don't know how I can put a handful of tests one after another (preferrably in the same line, with boolean operators) in a way that the whole expression returns False as soon as the first test evaluates to False.
Thanks for reading!
Your example should work.
if x and y and z:
...
Should happen only if none of x, y and z evaluate to False, and in Python, and short-circuits, so will return the False value as soon as one item fails. We can show this quite easily:
>>> def test(n):
... print("test", n)
... return n
...
>>> test(1) and test(2)
test 1
test 2
2
>>> test(0) and test(2)
test 0
0
>>> test(0) and test(2) and test(3)
test 0
0
>>> test(1) and test(0) and test(3)
test 1
test 0
0
I see your concern, but remember that whenever something is in an if statement in Python, it will be implicitly converted to bool for the conditional. Thus while 3 or 2 returns 3 and 3 and 2 returns 2 when done stand-alone, saying if 3 or 2 is actually equivalent to saying if bool(3 or 2), so you will get the falsey or truey value of what the logic returns when used in a conditional regardless of what the boolean logic would return in other contexts.
Yeah, I have to agree with the others in saying that your example should be working as you intend. You're right that x or y returns one of x, y, but that object will be able to be evaluated as True or False. That is how python evaluates if statements. It should work as written because your expressions will be evaluated in order and will return False once any test in the line returns as False (or 0, or [] or {} etc.). You can see that with a test that would raise an error if python actually tried it.
x = 1; y = 2
if x < y and x == y and d['a']: # d doesn't exist
print 'This will never be printed'
If your code isn't working as intended, please elaborate on exactly what you expect it to do, and what it is actually doing.
I made some assumptions about the code you did not include and added it to get the program running:
gotside = False
j = 2
i = 1
unit = 3
class A:
def __init__(self):
self.shape = [1, 4]
def __getitem__(self, pos):
return pos
a = A()
if (not gotside):
if (j > 1):
if (j < a.shape[1] - 1):
if a[i, j+unit]:
print("only now I do stuff!")
if (not gotside) and (j > 1) and (j < a.shape[1] - 1) and a[i, j+unit]:
print("I'm well tested but not so indented...")
For me this works with python 2.5, 2.6, 2.7 and 3.2:
only now I do stuff!
I'm well tested but not so indented...
Can you please check the above program if this works for you? If so, can you please give more information about the classes you use - especially the class of variable a.
The boolean and operator in Python (and most other programming languages) provides "short-circuit" functionality. This means, that if the fist term or the expression evaluates to false, the second term is not even evaluated:
>>> False and expensiveFunctionReturningBool()
False
The expensive function will never be called, because the Python interpreter immediately evalues the expression as False after the first term is determined to be False. This works, because in boolean logic, if one side of an and expression is false, the whole expression is false by definition
Python also uses short-circuit logic for or. In this case, if the first term is determined to be True, the second term is never evaluated.
>>> True or expensive()
True
Thus, boolean expressions can be used to collapse nested if statements (provided they are declared immediately one after another), and if they are used cleverly by keeping short-circuit logic in mind, they can also optimize conditional expressions.
Good Luck!

Categories

Resources