tags:

views:

526

answers:

7

What's the best Python idiom for this C construct?

while ((x = next()) != END) {
    ....
}

I don't have the ability to recode next().

update: and the answer from seems to be:

for x in iter(next, END):
    ....
+2  A: 

Maybe it's not terribly idiomatic, but I'd be inclined to go with

x = next()
while x != END:
    do_something_with_x
    x = next()

... but that's because I find that sort of thing easy to read

Blair Conrad
+1  A: 

What are you trying to do here? If you're iterating over a list, you can use for e in L where e is the element and L is the list. If you're filtering a list, you can use list comprehensions (i.e. [ e for e in L if e % 2 == 0 ] to get all the even numbers in a list).

FreeMemory
+5  A: 

It depends a bit what you want to do. To match your example as far as possible, I would make next a generator and iterate over it:

def next():
   for num in range(10):
      yield num

for x in next():
   print x
Johannes Hoff
+1  A: 

If you need to do this more than once, the pythonic way would use an iterator

for x in iternext():
    do_something_with_x

where iternext would be defined using something like (explicit is better than implicit!):

def iternext():
    x = next()
    while x != END:
        yield x
        x = next()
dF
+3  A: 

Short answer: there's no way to do inline variable assignment in a while loop in Python. Meaning that I cannot say:

while x=next():
    // do something here!

Since that's not possible, there are a number of "idiomatically correct" ways of doing this:

while 1:
    x = next()
    if x != END:
        // Blah
    else:
        break

Obviously, this is kind of ugly. You can also use one of the "iterator" approaches listed above, but, again, that may not be ideal. Finally, you can use the "pita pocket" approach that I actually just found while googling:

class Pita( object ):
    __slots__ = ('pocket',)
    marker = object()
    def __init__(self, v=marker):
        if v is not self.marker:
            self.pocket = v
    def __call__(self, v=marker):
        if v is not self.marker:
            self.pocket = v
        return self.pocket

Now you can do:

p = Pita()
while p( next() ) != END:
    // do stuff with p.pocket!

Thanks for this question; learning about the __call__ idiom was really cool! :)

EDIT: I'd like to give credit where credit is due. The 'pita pocket' idiom was found here

FreeMemory
Use of `__slots__` here is totally unnecessary.
Paul McGuire
+1  A: 

Can you provide more information about what you're trying to accomplish? It's not clear to me why you can't just say

for x in everything():
    ...

and have the everything function return everything, instead of writing a next function to just return one thing at a time. Generators can even do this quite efficiently.

Eli Courtwright
+13  A: 

@Mark Harrison's answer:

for x in iter(next_, END):
    ....

Here's an excerpt from Python's documentation:

iter(o[, sentinel])

Return an iterator object. ...(snip)... If the second argument, sentinel, is given, then o must be a callable object. The iterator created in this case will call o with no arguments for each call to its next() method; if the value returned is equal to sentinel, StopIteration will be raised, otherwise the value will be returned.

J.F. Sebastian