views:

67

answers:

3

I need to return two values at a time, so I have:

class IterableObject(object):
  def __iter__(self):
    for item in self.__dict__:
      return  self.__dict__[item + 1], self.__dict__[item]

So I can have:

myObj1, myObj2 = IterableObject()

value = myObj1.balance - myObj2.balance

Of course it did not work. What am I doing wrong? I think I can not add value on item like that.

+5  A: 

In the itertools documentation there is an example function called pairwise that you can copy into your project:

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return izip(a, b)

Use it like:

for x1, x2 in pairwise(some_iterable):
    # etc..

Note that when you iterate over a dict the items are not necessarily returned in order, so you should sort first.

Mark Byers
thanks but is there a simpler way to do this without going the route of itertools?
Spikie
+1  A: 

A possible solution without itertools:

def pairwise(iterable):
    it = iter(iterable)
    try:
        while True:
            yield it.next(), it.next()
    catch StopIteration:
        pass

>>> list(pairwise(range(6))
[(0, 1), (2, 3), (4, 5)]
>>> list(pairwise(range(5))
[(0, 1), (2, 3)]

This is different from the solution in the itertools documentation in the sense that the last item is never returned from the iterable if it happens to contain an odd number of elements. But I guess the solution in the itertools examples is better.

Tamás
+1  A: 

A slight modification to your own example should give you what you want. Your original example shows that you don't know that iterating over a dictionary gives you the keys of the dictionary. "aproprty_name" + 1 will almost never give you what you want.

class IterableObject:
  def __iter__(self):
    properties = (i for i in self.__dict__)
    While True:
      a = properties.next()
      try:
        b = properties.next()
      except StopIteration:
        yield (getattr(self,a), ) #for the odd number of properties case
        raise StopIteration
      yield getattr(self, a), getattr(self, b)

This will not work in the example you present. You can not blindly anticipate the values being in any order that would make subtracting one from the other make sense.

What you probably want is an object that returns the next two values from a list of values that you know to be an even number of values. You will have to set that list in the object. That way the paired in order sequence would be passed back in the same order.

class PairedList:
  def __iter__(self):
    balances = iter(self.balances)
    while True:
      yield balances.next(), balances.next()

>>> b = PairedList()
>>> b.balances = (2000, 151, 1000, 255, 600, 150, 0, 20, 30, 30, 50, 10)
>>> [i for i in b]
[(2000, 151), (1000, 255), (600, 150), (0, 20), (30, 30), (50, 10)]
>>> [(balance-withdrawal, balance, withdrawal) for balance, withdrawal in b]
[(1849, 2000, 151), (745, 1000, 255), (450, 600, 150), (-20, 0, 20), (0, 30, 30), (40, 50, 10)]

You might want to reread you question and example and rephrase them because as written you are creating a new object and expecting it to already contain your values. An example using my PairedList class that would do this for you would be:

>>> PairedList.balances = b.balances
>>> [(balance-withdrawal, balance, withdrawal) for balance, withdrawal in PairedList()]
[(1849, 2000, 151), (745, 1000, 255), (450, 600, 150), (-20, 0, 20), (0, 30, 30), (40, 50, 10)]

But this is almost certainly not what you want. It would by default limit you to only ever having one set of balances that you could iterate over. And would create a default set of balances for every PairedList object which will eventually come back to bite you in the butt.

freegnu