Understanding and, or operations in Python [duplicate] - python

This question already has answers here:
Logical operators in Python [duplicate]
(4 answers)
Closed 5 years ago.
I am trying some operations in Python but I am not understanding the underlying concept of it. I tried various combinations which might be bit tough for you but my objective was how it is working internally in Python.Please find the code below:
>>> 2 or 3
2
>>> 3 or 2
3
>>> 3 or 3
3
>>> 3 or -3
3
>>> -3 or 3
-3
>>> 0 or 3
3
>>> 0 or -9
-9
>>> 3 and 4
4
>>> 3 and 6
6
>>> 0 or None
>>> 0 and None
0
>>> None and 0
>>> None or 0
0
>>> 5 and 2
2
>>> -3 and 6
6
>>> 3 and -6
-6
>>> 3 and 0
0
>>> 0 and 0
0
>>> 0 and 0.0
0
>>> 0.0 and 0
0.0
>>> 0.0 or 0
0
>>> 0 or 0.0
0.0
>>> [] or 3
3
>>> 3 or []
3
>>> 0 or []
[]
>>> [] or 0
0
>>> [] and 3
[]
>>> 3 and []
[]
>>> [] or {}
{}
>>> [] and {}
[]
>>> [] and {}
[]
>>> {} or []
[]
>>> {} and []
{}

This is actually very well described in most tutorials; the general rule is: a and b is b if a is true, else it is a; a or b is a if a is true, else it is b. Now, False, None, (), [], {}, '', 0 and 0.0 are all considered false; practically everything else is true.

I believe you are referring to how truth tables work here. See the following link:
https://en.wikibooks.org/wiki/Non-Programmer%27s_Tutorial_for_Python_3/Boolean_Expressions
Hope it helps.

I think you are expecting and and or to produce a boolean value, that is, True or False. But they don't. or will return the first operand if that evaluates to True; otherwise it will return the second operand. and will return the first operand if that evaluates to False; otherwise it will return the second operand. For the evaluation, the following count as False: zero integers and floats, the empty string, and empty tuples, lists and dicts. Anything else counts as True, including, for example, the string "0".

This is short-circuiting in action:
a and b
a is False -> a immediately returned
a is True, b is False -> b immediately returned
both True -> the last object is returned (b)
a or b
a is True -> a is immediately returned
a is False, b is True -> b is returned
both False -> the last object returned (b)
Now, some values are considered 'falsey', e.g. bool(value) == False, for example:
False itself
the number zero (0, 0.0, 0 + 0j)
empty containers ([], tuple(), "", {}, set())
None
anything else whose __bool__ method returns False
Others are considered 'truthy'.

Related

Python debugging simple script

So as part of a script I'm writing to play tic tac toe, I have a 'win checker' which takes as its input:
a list of numbers which denote positions
who started the game
It's not really important for the problem I'm having, but I thought some background might help. Here is the code:
import matplotlib.pyplot as plt
import math
import numpy as np
import random
import pdb
def win_checker(position_list, turn2):
win_list1 = []
win_list2 = []
for bud in xrange(len(position_list)):
if bud % 2 == 0:
win_list1.append(position_list[bud])
print win_list1
if 1 and 2 and 3 in win_list1:
return True
if 4 and 5 and 6 in win_list1:
return True
if 7 and 8 and 9 in win_list1:
return True
if 1 and 4 and 7 in win_list1:
return True
if 2 and 5 and 8 in win_list1:
return True
if 3 and 6 and 9 in win_list1:
return True
if 1 and 5 and 9 in win_list1:
return True
if 3 and 5 and 7 in win_list1:
return True
elif bud % 1 == 0:
win_list2.append(position_list[bud])
print win_list2
if 1 and 2 and 3 in win_list2:
return True
if 4 and 5 and 6 in win_list2:
return True
if 7 and 8 and 9 in win_list2:
return True
if 1 and 4 and 7 in win_list2:
return True
if 2 and 5 and 8 in win_list2:
return True
if 3 and 6 and 9 in win_list2:
return True
if 1 and 5 and 9 in win_list2:
return True
if 3 and 5 and 7 in win_list2:
return True
else:
return False
Then when I try the script for a certain position:
win_checker([5,1,3,2], 1)
[5]
[1]
[5, 3]
Out[57]: True
I don't understand why the output is True, if someone could explain what I'm missing that would be very helpful to me
Detail of the problem:
The and operator works on boolean values only. It does not distribute over the in operator (remember the distributive law of multiplication over addition?). Your expression
1 and 2 and 3 in win_list1
becomes
bool(1) and bool(2) and bool (3 in win_list1)
bool(n) is False for n=0, True for everything else.
Immediate fix:
Alex Hall already gave you that
Better fix (perhaps):
Renumber your array of choices to be a magic square:
6 7 2
1 5 9
8 3 4
Now, all you have to do is check whether you have a sum of 15 for any combination of three chosen positions. You can generate all of those with
itertools.combinations(win_list1, 3)
This would reduce your checking from 18 lines to 1 (or 2-4, if you prefer that readability).
Extra issue:
Your logic on bud is a little weird. I do understand the odd/even checking on the turn number:
if bud % 2 == 0:
However, the second one,
elif bud % 1 == 0:
is True for any integer. The percent sign is the modulus operator: divide by the mod and keep the remainder. In short, the second one is always true. Just make it an else.
Another ...
Why not make win_list a 2-D list? Use win_list[0] and win_list[1], so you can fold their code together. You can simply have
player = bud % 2
win_list[player].append(position_list[bud])
if any(sum(itertools.combinations(win_list[player], 3)) == 15):
...
if 1 and 5 and 9 in win_list2:
should be:
if 1 in win_list2 and 5 in win_list2 and 9 in win_list2:
In python
>> 1 and 2 and 3 in win_list1
is evaluated as
>> 3 in win_list1
which is True

assigning values to 2d list using for loop in python not working correctly [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 5 years ago.
Suppose I do the following:
>>> l = [[]]*2
>>> l
[[], []]
>>> l[0].append(1)
>>> l
[[1], [1]]
Why does 1 get appended to both lists?
[[]]*2 is a list of two references to the same list. You are appending to it and then seeing it twice.
Because there is really only one list. Consider this:
>>> l = [[]]
>>> l2 = l*2
>>> l2[0] is l[0]
True
>>> l2[1] is l[0]
True
*2 performed on a list does not copy the list but return a list of length 2 filled with the same reference.
What you probably wanted was this:
>>> l = [[] for _ in xrange(2)]
As #Asterisk mentions in a comment, the same behaviour is exposed by all common collections. As a rule of thumb it is therefore best to only use multiplication on immutable types with value-semantics.
Showcasing the difference with memory layout:
listOfLists = [[]] * 3
listOfListsRange = [[] for i in range(0, 3)]
Here's how i initialize a list of lists. Rows vary slowest.
nrows = 3; ncols = 5
l_of_ls = [[0]*ncols for i in range(nrows )]
for rix, r in enumerate(l_of_ls):
for cix, c in enumerate(r):
print rix, cix, 'val = ',c
RESULT
0 0 val = 0
0 1 val = 0
0 2 val = 0
0 3 val = 0
0 4 val = 0
1 0 val = 0
1 1 val = 0
1 2 val = 0
1 3 val = 0
1 4 val = 0
2 0 val = 0
2 1 val = 0
2 2 val = 0
2 3 val = 0
2 4 val = 0
Also Worth Noting for Indexing Purposes
for rix in range(nrows):
for cix in range(ncols):
print l_of_ls[rix][cix],
print
RESULT
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0

Python If statement : how to equate to a list

I have written a program that eliminates the items in a list and outputs the other list.
Program :
r = [5,7,2]
for i in range(10):
if i != r:
print i
It outputs
0
1
2
3
4
5
6
7
8
9
But I want the desired output to be
0
1
3
4
6
8
9
What is the method to do so?
When you do - i !=r its always true, because an int and a list are never equal. You want to use the not in operator -
r = [5,7,2]
for i in range(10):
if i not in r:
print i
From python documentation -
The operators in and not in test for collection membership. x in s evaluates to true if x is a member of the collection s, and false otherwise. x not in s returns the negation of x in s .
You are checking if a integer is not equal to to list .which is right so it prints all the value
What you really wanted to do is check if the value is not available in the list .So you need to use not in operator
r = [5,7,2]
for i in range(10):
if i not in r:
print i
You can try like this,
>>> r = [5, 7, 2]
>>> for ix in [item for item in range(10) if item not in r]:
... print ix
...
0
1
3
4
6
8
9
Using set
>>> r = [5,7,2]
>>> for i in set(range(10))-set(r):
... print(i)
...
0
1
3
4
6
8
9
>>>

Converting matlab program to equivalent python code

In want to implement the below listed Matlab commands in Python. I am able to figure out the Matlab equivalent commands in Python, but i am not getting the exact result. Can someone please help me to achieve so.
MATLAB CODE:
n0 = 3
n1 = 1
n2 = 5
n = [n1:n2]
>> 1 2 3 4 5
x = [(n - n0) == 0]
>> 0 0 1 0 0
PYTHON CODE:
import numpy
n0 = 3
n1 = 1
n2 = 5
n = r_[n1:n2+1]
>> [1 2 3 4 5]
x = r_[(n-n0) == 0]
>> [False False True False False]
So x is my array with boolean data type " [array([False, False, True, False False], dtype=bool)]". How can i make my last command to return result in form of 0's or 1's such that result is exactly same as Matlab.
use a list comprehension to convert bool to int:
[int(val) for val in x]

Why does appending to one list also append to all other lists in my list of lists? [duplicate]

This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 5 years ago.
Suppose I do the following:
>>> l = [[]]*2
>>> l
[[], []]
>>> l[0].append(1)
>>> l
[[1], [1]]
Why does 1 get appended to both lists?
[[]]*2 is a list of two references to the same list. You are appending to it and then seeing it twice.
Because there is really only one list. Consider this:
>>> l = [[]]
>>> l2 = l*2
>>> l2[0] is l[0]
True
>>> l2[1] is l[0]
True
*2 performed on a list does not copy the list but return a list of length 2 filled with the same reference.
What you probably wanted was this:
>>> l = [[] for _ in xrange(2)]
As #Asterisk mentions in a comment, the same behaviour is exposed by all common collections. As a rule of thumb it is therefore best to only use multiplication on immutable types with value-semantics.
Showcasing the difference with memory layout:
listOfLists = [[]] * 3
listOfListsRange = [[] for i in range(0, 3)]
Here's how i initialize a list of lists. Rows vary slowest.
nrows = 3; ncols = 5
l_of_ls = [[0]*ncols for i in range(nrows )]
for rix, r in enumerate(l_of_ls):
for cix, c in enumerate(r):
print rix, cix, 'val = ',c
RESULT
0 0 val = 0
0 1 val = 0
0 2 val = 0
0 3 val = 0
0 4 val = 0
1 0 val = 0
1 1 val = 0
1 2 val = 0
1 3 val = 0
1 4 val = 0
2 0 val = 0
2 1 val = 0
2 2 val = 0
2 3 val = 0
2 4 val = 0
Also Worth Noting for Indexing Purposes
for rix in range(nrows):
for cix in range(ncols):
print l_of_ls[rix][cix],
print
RESULT
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0

Categories