How to iterate over the data attributes of an instance object, returning two values ​​at once?

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:

myObj1, myObj2 = IterableObject()

value = myObj1.balance - myObj2.balance

      

Of course it didn't work. What am I doing wrong? I think I cannot add value for this item.

+2


a source to share


3 answers


There is an example named function in the itertools documentationpairwise

that you can copy to 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, the dict

items do not necessarily come back in order, so you must sort first.

+5


a source


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 differs from the solution in the itertools documentation in the sense that the last element is never returned from the iterable if it happens to contain an odd number of elements. But I think the solution in examples is itertools

better.

+1


a source


A slight modification of 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 are presenting. You cannot blindly foresee that the values ​​are in any order that subtracts one from another meaning.

What you probably want is an object that returns the next two values ​​from a list of values, which are known to be an even number of values. You will need to set this list on an object. Thus, the paired sequence will be transmitted 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 the question and example and rephrase them, because as written, you are creating a new object and expect it to contain your values ​​already. An example using my PairedList class that will 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. This will by default limit you to only having one set of balances that you could iterate over. And will create a set of default balances for each PairedList object that will eventually come back to bite you in the butt.

+1


a source







All Articles