[Tutor] Variations on putpixel - More Pixel manipulation - #14

Kent Johnson kent37 at tds.net
Wed Jun 1 12:04:07 CEST 2005


D. Hartley wrote:
> Rudy,
> I have the im.getpixel incrementing at every pixel by i (in a for loop
> for each pixel in wire.png), and I know incrementing the xy in the new
> one goes like this:
> 
> x + 1
> y + 1
> x - 1
> x - 1
> y - 1
> y - 1
> x + 1
> x + 1
> x + 1 ... etc
> 
> First the x and then the y is incremented by 1, then that 1 is made
> negative and the # of times += 1.  then, back around, then the 1 is
> made positive again, and so on.
> 
> But how can I increment a changing "to_coordinate" variable in this
> weird way each time while still only incrementing the
> "from_coordinate" by 1 in a for loop? I keep trying to set up my
> function and only being able to change one or the other at a time!

Denise,

You are essentially trying to iterate two sequences at the same time. One is the simple sequence 0, 
1, 2, 3, ...; the other is the more complex sequence of (x, y) pairs in the "to" coordinates.

There are a couple of good ways to do this in Python. Suppose you have a loop that calculates and 
uses successive values of (x, y) based on some state and the previous values of x and y:

x, y = initialX, initialY
state = initialState
while True:
   x, y, state = calculateXY(x, y, state)
   doSomething(x, y)

Now suppose doSomething() needs another argument from the sequence 0, 1, .... One option is to add 
the calculations for the new sequence to the loop:

x, y = initialX, initialY
i = initialI
state = initialState
while True:
   x, y, state = calculateXY(x, y, state)
   i = calculateI(i)
   doSomething(x, y, i)

What if i is actually coming from another sequence rather than being calculated? You can control 
iteration over a sequence by creating an explicit iterator and calling next() on it when you need a 
new element:

x, y = initialX, initialY
iIter = iter(iSequence)
state = initialState
while True:
   x, y, state = calculateXY(x, y, state)
   doSomething(x, y, iIter.next())

This works but it conflates three things - iteration over (x, y), iteration over iSequence, and 
proccessing of the triples (x, y, i). A nice way to break these apart is to create a generator 
function that yields (x, y) pairs:

def generateXY():
   x, y = initialX, initialY
   state = initialState
   while True:
     x, y, state = calculateXY(x, y, state)
     yield (x, y)

Notice this is almost identical to the original loop; the call to doSomething() has been replaced by 
a yield.

Calling generateXY creates a generator object which itself can be iterated. Now, with the help of 
zip(), you can easily iterate the (x, y) pairs and the iSequence elements together:

for (x, y), i in zip(generateXY(), iSequence):
   doSomething(x, y, i)

(Note the cool use of tuple unpacking too!)

Kent



More information about the Tutor mailing list