Python: for statement behavior - python

My question concerns the output of this statement:
for x in range(4), y in range(4):
print x
print y
Results in:
[0, 1, 2, 3]
2
True
2
It seems there is a comparison involved, I just can't figure out why the output is structured like this.

My guess is that you're running this from an interactive console, and already had y defined with a value of 2 (otherwise, you'd get NameError: name 'y' is not defined). That would lead to the output you observed.
This is due to for x in range(4), y in range(4): actually being equivalent to the following when evaluated:
for x in (range(4), y in range(4)):
which reduces to...
for x in ([0,1,2,3], 2 in range(4)):
which again reduces to...
for x in ([0,1,2,3], True):
This then results in 2 iterations of the for loop, since it iterates over each element of the tuple:
x = [0,1,2,3]
x = True.
(And of course, y is still 2.)

You've created a weird, weird thing there.
>>> y = 2
>>> range(4), y in range(4)
([0, 1, 2, 3], True)
The y in range(4) is a membership test.
The range(4), y in range(4) is a pair of items; a tuple.
The variable x is set to range(4), then the result of y in range(4).
The variable y is just laying around with a value; it is not set by the for statement.
This only works hacking around on the command line typing random stuff with y left laying around.
This isn't sensible Python code at all.
[And yes, the word in has two meanings. So do ()'s and several other pieces of syntax.]

You seem to have y defined prior to running this code. What you're iterating over is a two-item tuple: first item is range-generated list, second is True, which is result of the y in range(4):
>>> y = 2
>>> for x in range(4), y in range(4):
print x, 'x'
print y, 'y'
[0, 1, 2, 3] x
2 y
True x
2 y
What I suspect you were trying to do is to iterate over two variables from two lists. Use zip for this.

Dav nailed down perfectly why the syntax you wrote doesn't work.
Here are the syntaxes that do work for what you're probably trying to do:
If you want all 4 x 4 combinations for x and y, you want 2 nested loops:
for x in range(4):
for y in range(4):
print x, y
Or if you really want to use one loop:
import itertools
for (x, y) in itertools.product(range(4), range(4)):
print x, y
itertools.product() generates all possible combinations:
This is less readable than 2 loops in this simple case, but the itertools module has many other powerful functions and is worth knowing...
If you want x and y to advance in parallel over two sequences (aka "lock-step" iteration):
for (x, y) in zip(range(4), range(4)):
print x, y
# `zip(range(4), range(4))` is silly since you get x == y;
# would be useful for different sequences, e.g.
# zip(range(4), 'abcd')
[Background: The name zip comes from Haskell; think about how a Zipper takes one tooth from here and one from there:
zip() cuts off to the length of the shortest sequence; the itertools module has other variants...]

Related

Understanding quantifiers in z3

I'm trying to understand this example:
solve([y == x + 1, ForAll([y], Implies(y <= 0, x < y))])
but after reading the explanation I still don't understand it.
How do you read this?
what is the meaning of []?
My wrong interpretation of this is.
"Given the theorem y == x + 1. Does it hold for all y such that Implies(y <= 0, x < y)?"
With this interpretation if I use y = 0 and x = -1 every constraint (Implies(y <= 0, x < y) is true since y <= 0 and x < y) is respected, but If I run this I find out that it's not solvable.
Do you have any hits to how to understand this topic?
Looks like there're a couple of confusions here. Let's first sort out binding: In a quantifier context, the variable is independent, i.e., it can be renamed with no change to the semantics. So, your original:
from z3 import *
x, y = Ints('x y')
solve([y == x + 1, ForAll([y], Implies(y <= 0, x < y))])
is exactly equivalent to:
from z3 import *
x, y, z = Ints('x y z')
solve([y == x + 1, ForAll([z], Implies(z <= 0, x < z))])
Note that we replaced the y in the "scope" of ForAll to z, but left the one in the first conjunct untouched. You can only rename within the scope of ForAll (or Exist), not outside of it.
And both of these equivalent expressions are unsatisfiable. Why? The first conjunct is easy to satisfy; just pick an arbitrary x, and set y to be x+1 and you're done. It's the second conjunct that's unsatisfiable. Because, no matter which x you choose to satisfy the first, you can always find a z that's less than that x (just pick min(0, x-1)), and the quantified formula becomes False for that assignment. And hence there are no solutions.
Now, let's consider the variant you had in your comments, with x > z:
from z3 import *
x, y, z = Ints('x y z')
solve([y == x + 1, ForAll([z], Implies(z <= 0, x > z))])
Again, the first conjunct is easy to satisfy. And this time, so is the second, because you can pick a positive x, and that will be greater than all z's so long as z <= 0, and thus the implication is always true. And that's exactly what z3 is telling you, when it gives you the satisfying assignment:
[x = 2, y = 3]
Note that there's nothing in this assignment regarding the variable z. You cannot really give a model for a universally quantified formula; by definition it is true for all values of z.
Hope this clears things up.
[] is a Python list; the outer one is a list of constraints (representing a conjunction) and the one in the ForAll is a list of constants to bind.
Note that the same constant name can be re-used. In this case, y in y == x + 1 is a global existential and the y in the ForAll is a universally bound variable which also has the name y.

What does "x" mean in "for x in range(10):"?

I'm curious what x means when you look at this:
import random
for x in range(10):
print random.randint(1,101)
x itself has no special meaning, it simply (as a part of the for loop) provides a way to repeat
print random.randint(1,101)
10 times, regardless of the variable name (i.e., x could be, say, n).
In each iteration the value of x keeps increasing, but we don't use it. On the other hand, e.g.,
for x in range(3):
print(x)
would give
0
1
2
For x in range(3) simply means,
for each value of x in range(3), range(3) = 0,1,2
As it is range(3), the loop is looped three times and at each time, value of x becomes 0, then 1 and then 2
Here, x is just a variable name used to store the integer value of the current position in the range of loop and it iterates through out the range of a loop.
Like in for x in range(10):
x iterates 10 times and for instance in your for loop above, during the first iteration of the loop x = 1, then x=2 for the next iteration then, x= 3 and so on...
It is not neccessary to take x as a variable only you can take any variable name like i,a etc...
X is a variable name, so could be any name allowed by python for variable names. As a variable , it’s value will be different every time the loop circle ends, in this particular loop range(10) the value of x will start in 0 and next 1 , and next 2, until reach value of 10
so If you want to print a random int:
for x in range(10):
print(random.randint(x))
also, if it is python3.X, print(x) not print x, second is python2.X
I am coming from a short intro in C, and I was confused by the 'x' as well. For those coming from C,C++,C# etc.:
The 'x in range(10)' is the same thing as doing this in C:
for (x = 0; x < 10; x++)

Unpacking a tuple in python and iterating over it

I'm trying to unpack a co-ord tuple then iterate over it to blit a sprite multiple times:
def updateMap(self, playerPosition):
self.x_coord, self.y_coord = playerPosition
t = Tree(self.screen)
for x in range(self.x_coord):
for y in range(self.y_coord):
self.screen.fill((0,104,0))
t.drawTree((x, y))
However I get the following error:
File "unnamed.py", line 26, in updateMap
for x, y in range(self.x_coord), range(self.y_coord):
ValueError: need more than 0 values to unpack
Grateful if someone can point me in the right direction on the correct way to do this. Thanks.
EDIT: I have edited my code to the above to iterate over every coord say if playerPostion is 0,5 so the iteration goes (0,1) (0,2) (0,3) (0,4) (0,5) -- but although I'm not getting any errors it seems the tree does not get drawn correctly. Thanks.. it seems to be the answer, except my coding is just wrong.
I think this is what you want instead:
from itertools import product
self.x_coord, self.y_coord = playerPosition #playerPosition is a tuple
t = Tree(self.screen)
for x,y in product(range(self.x_coord+1), range(self.y_coord+1)):
self.screen.fill((0,104,0))
t.drawTree((x, y))
I think the OP wants to iterate over the range of X co-ordinates and the range of Y co-ordinates to create a (x,y) for each case.
for x in range(self.x_coord):
for y in range(self.y_coord):
print(x, y)
Use the built in Python zip function assuming both of the iterables are of the same length. If not then you will need to do a bit of sanitization before to ensure they are.
for x, y in zip(range(self.x_coord), range(self.y_coord))
Maybe if you change:
self.x_coord = 0
self.y_coord = 0
playerPosition = self.x_coord, self.y_coord
to:
self.x_coord, self.y_coord = playerPosition
then you get the player position x and y in to self.x_coord and self.y_coord
And to iterate over every combination of x and y you either need to put a loop over y range inside inside a loop over the x range
for x in range(self.x_coord):
for y in range(self.y_coord):
self.screen.fill((0,104,0))
t.drawTree((x, y))

Iterate through 2D List, assign each value on a row in the list to a variable, repeat for each row - python

I have a list comprising a number of X,Y values
aList = [[1, 2],[3, 4],[5, 6],[7, 8]]
i.e. X = 1, Y = 2
I need to extract each X and Y value on a row separately, assign those values to an X and Y variable respectively, and then act on the X and Y values.
This should then loop to the next row where the same process would occur again. I'll use print instead of the excessive code that needs to occur after this loop.
i.e. loop starts, X is assigned 1, Y is assigned 2, X and Y are used as inputs in formula, loop ends (and repeat for the remaining values in this list)
aListLen = len(aList)
aListRows = len(aList)
aListCols = len(aList[0])
The following code only extracts values 1 by one in the list
for row in range(aListRows):
for column in range(aListCols):
X = aList[row][column]
print X
adding a Y variable as follows results in an error
for row in range(aListRows):
for column in range(aListCols):
X = a[row][column]
Y = a[row][column+1]
print X
print Y
Looking at it now, I'm not sure the following if/elif loop would work as the X and Y values need to go in a formula together.
I could add an if/elif statement under the 2nd loop, but I'd still need to have a way of forcing the 2nd loop to repeat. (Which brings us back to the original problem anyway)
for row in range(aListRows):
for column in range(aListCols):
if column == 0:
X = aList[row][column]
elif column == 1:
Y = aList[row][column]
How can I force the loop to restart once the X value has been provided?
I assume the loop would then repeat, this time providing the value for Y.
Is there a better way of doing this?
Should point out this is Python 2.7 (so I cannot use anything exclusive to Python 3)
You're looping over the indices of the inner list and adding 1 to them. This will cause an IndexError when column contains the value of aListCols, since len(a[row]) == column+1
I think you are looking for this:
In [17]: aList = [[1, 2],[3, 4],[5, 6],[7, 8]]
In [18]: for X,Y in aList:
....: print "X value is %s, Y value is %s" %(X, Y)
....:
X value is 1, Y value is 2
X value is 3, Y value is 4
X value is 5, Y value is 6
X value is 7, Y value is 8
To assign the variables instead of printing them you could do:
for X,Y in aList:
tempX = X
tempY = Y
At the first iteration tempX will have a value of 1, tempY will have a value of 2. At the second iteration tempX will be 3, tempY will be 4...
You could, instead of a loop, use a recursive function.
Basically, that is a function that calls itself. For example:
def myfunction():
(something happens that wants you to start the function over)
myfunction()
Hence, it will call the function again, forcing the code to go back to the top.

List comprehension for loops Python

I use a lot of N dimensional arrays and it gets a pain to have to write such indented code and I know some codes can be replaced with list comprehensions and inline statements. For example:
for x in (0,1,2,3):
for y in (0,1,2,3):
if x < y:
print (x, y, x*y)
can be replaced with:
print [(x, y, x * y) for x in (0,1,2,3) for y in (0,1,2,3) if x < y]
But how could I change the action instead of print to do something else like:
total = x+y
So what I want to do is something like:
[(total+=x+y) for x in (0,1,2,3) for y in (0,1,2,3) if x < y]
However this doesn't work
Is there a smart way to do this rather than:
for x in (0,1,2,3):
for y in (0,1,2,3):
if x < y:
total+=x+y
sum works here:
total = sum(x+y for x in (0,1,2,3) for y in (0,1,2,3) if x < y)
As an alternative to writing loops N levels deep, you could use itertools.product():
In [1]: import itertools as it
In [2]: for x, y in it.product((0,1,2,3),(0,1,2,3)):
...: if x < y:
...: print x, y, x*y
0 1 0
0 2 0
0 3 0
1 2 2
1 3 3
2 3 6
This extends naturally to N dimensions.
Use numpy. This lets you use arrays that add up like vectors:
x = numpy.arange(3)
y = numpy.arange(3)
total = x + y
With the modified question, add a call to sum as well
total = numpy.sum(x+y)
Reduce function directly reduces collective items to single item. You can read more about them here, but this should work for you:
total=reduce(lambda x,y:x+y,range(4))
or
total=reduce(lambda x,y:x+y,(0,1,2,3))
Another possibility is:
for x,y in ((x,y) for x in (0,1,2,3) for y in (0,1,2,3) if x < y):
print (x, y, x * y)
In this way you can iterate over anything you'd use in a list comprehension without actually creating the comprehended list (if you get my meaning ;) If comprehended list is big, maybe so big it saturates or even doesn't fit in memory, that's quite handy..

Categories

Resources