How to iterate over an instance object's data attributes, returning two values at a time?
I need to return two values at a time, so I have:
class IterableO开发者_StackOverflow社区bject(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.
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.
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.
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.
精彩评论