[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