如何遍历实例对象的数据属性,每次返回两个值?

2 投票
3 回答
1156 浏览
提问于 2025-04-15 21:32

我需要一次返回两个值,所以我写了:

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

这样我就可以得到:

myObj1, myObj2 = IterableObject()

value = myObj1.balance - myObj2.balance

当然,这样并没有成功。我哪里做错了呢?我觉得我不能这样给项目添加值。

3 个回答

1

你可以稍微修改一下你自己的例子,就能得到你想要的结果。你原来的例子说明你不知道遍历一个字典会得到字典的键。"aproprty_name" + 1 几乎不会给你想要的结果。

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)

在你提供的例子中,这样做是行不通的。你不能盲目地期待这些值会以某种顺序出现,这样才能让相减变得有意义。

你可能想要的是一个对象,它可以从你知道的偶数个值的列表中返回下两个值。你需要在这个对象中设置那个列表。这样,成对的顺序就会按原来的顺序返回。

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)]

你可能需要重新阅读一下你的问题和例子,并重新表述一下,因为按照你写的方式,你是在创建一个新对象,并期待它已经包含了你的值。使用我的 PairedList 类的一个例子可以帮你做到这一点:

>>> 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)]

但这几乎肯定不是你想要的。默认情况下,这样做会限制你只能有一组可以遍历的余额。而且每个 PairedList 对象都会创建一组默认的余额,这最终会给你带来麻烦。

1

这里有一个可能的解决办法,不用到 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)]

这个方法和 itertools 文档 中的解决方案不太一样,因为如果可迭代的对象里有奇数个元素,最后一个元素是不会被返回的。不过我觉得 itertools 例子里的解决办法更好。

5

itertools的文档中,有一个叫做pairwise的示例函数,你可以把它复制到你的项目里:

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

使用方法如下:

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

需要注意的是,当你遍历一个dict(字典)时,里面的项目不一定是按顺序返回的,所以你最好先进行排序。

撰写回答