【问题标题】:Python iteration of list of objects "not iterable"对象列表的Python迭代“不可迭代”
【发布时间】:2014-04-26 15:14:37
【问题描述】:

Python 新手,但我已经研究了几个小时。如果我遗漏了一些明显的东西,请原谅我。

我有一个名为 LineItem 的类,它有一个属性 _lineItems,即属于给定 LineItem 的 LineItem 列表。基本上是一个子列表。

我想打印一个 LineItem 及其所有子项(以及子项自己的子项),但我在迭代时遇到了问题。

from decimal import * 
class LineItem(object):
    """
    Instance attributes:
      amount: Decimal
      _lineItems: list of child internal lineitems (possibly an empty list)
      isInternal: bool
    """

    def __init__(self, **kw):
        self.amount = Decimal(0)
        self._lineItems = []
        self.isInternal = False
        for k, v in kw.items():
            setattr(self, k, v)

给我带来麻烦的示例 LineItem 在下面定义为 ext2,有三个孩子。

# External line item with one level of children
int1 = LineItem(amount=Decimal('1886.75'), description='State Dues',
         isInternal=True)
int2 = LineItem(amount=Decimal('232.50'), description='National Dues',
         isInternal=True)
int3 = LineItem(amount=Decimal('50'), description='Processing Fee',
         isInternal=True)
ext2 = LineItem(amount=Decimal('2169.25'), description='Dues',
         _lineItems=[int1, int2, int3])

我有这个递归函数来迭代所有子项(并打印它们的编号,例如 1、2、2.1 作为第二项的第一个子项等)

def print_line_item(LineItems):
    count = 1
    for a in LineItems:
        print count, ' ', a.description, ' (', a.amount, ')'
        if a._lineItems != []:
            for b in a._lineItems:
                print count, '.', print_line_item(b),
        count+=1

但是当我尝试使用它时

def main():
    print_line_item([ext1, ext2, ext3]) #ext1 has no children, prints fine
if __name__=="__main__":
    main()

我明白了

line 56, in print_line_item
    print count, '.', print_line_item(b),
line 51, in print_line_item
    for a in LineItems:
TypeError: 'LineItem' object is not iterable

好吧,不知何故我搞砸了列表。

如果我添加几个打印语句:

def print_line_item(LineItems):
    count = 1
    for a in LineItems:
        print count, ' ', a.description, ' (', a.amount, ')'
        if a._lineItems != []:
            print a._lineItems
            for b in a._lineItems:
                print b
                print count, '.', print_line_item(b),
        count+=1

我得到证明 a._lineItems 确实是一个列表,打印如下:

[<__main__.LineItem object at 0x0227C430>, <__main__.LineItem object at 0x0227C5F0>, <__main__.LineItem object at 0x0227C670>]

我试图传递给递归调用的 b 是单个 LineItem 的内存地址

<__main__.LineItem object at 0x0227C430>

那么,我实际上应该怎么做我想做的事?我用 .iter 或 ___iter___ 尝试了几件事,但没有运气。

此外, if a._lineItems != [] 似乎也不起作用(也没有变化)。我得到“无”的打印行

【问题讨论】:

  • 不要使用!= [],使用if a._lineItemsif len(a._lintItems)。另外,不要挑剔,但这不是递归。
  • 您如何将您的问题精简为一个简单的最小可重现示例?
  • @sberry 怎么不是递归的? print_line_item 通过子列表调用自身
  • SSCCE 是个好主意。另外,你可以试试 pylint——它就像一个关于如何编写好的 Python 代码的专家系统。
  • (短,自包含,正确(可编译),示例是 SSCCE 的意思)

标签: python list object iteration


【解决方案1】:
def print_line_item(LineItems):
    count = 1
    for a in LineItems:
        print count, ' ', a.description, ' (', a.amount, ')'
        if a._lineItems != []:
            for b in a._lineItems:
                print count, '.', print_line_item(b),
        count+=1

它可能是正确的版本,未经测试。

def print_line_item(LineItems, precedingNumber='1'):
    count = 1
    for a in LineItems:
        print precedingNumber, '.', count, ' ', a.description, ' (', a.amount, ')'
        print_line_item(a._lineItems, precedingNumber + '.' + count),
        count+=1

【讨论】:

  • 谢谢梅卢格。这还不够,但你让我比其他任何人都更接近解决方案。
【解决方案2】:

你收到一条不可迭代的消息是有道理的——你实际上是在为列表中的每个项目递归到 print_line_item——迟早,你会在列表中遇到不可迭代的东西它本身——然后你继续调用它的 print_line_item(),它会尝试迭代它。

如果你想问“这个项目是一个列表吗?”你可以使用isinstance(some-object, list)。或者,如果您想允许其他可迭代但非列表的事物,您可以使用 if isinstance(some-object, collections.Iterable)(您必须导入集合)。

【讨论】:

  • 嗨,JoeL,我听到你在说什么,这就是为什么“if a._lineItems != []:”在那里 - 它无论如何都不能正常工作,但在这个例子中,我无论如何,不​​应该达到那个基本情况。我正在尝试迭代一个列表,我通过在尝试迭代之前将其打印出来证明了它是一个列表。这就是我被卡住的地方(除非我仍然误解?)
  • "if a._lineItems != []" 表示“如果 a.lineItems 不是空列表”,而不是“如果它不是列表”。
猜你喜欢
  • 2023-03-07
  • 1970-01-01
  • 2015-10-23
  • 1970-01-01
  • 1970-01-01
  • 2021-12-13
  • 2013-12-01
  • 2015-04-14
  • 2022-07-01
相关资源
最近更新 更多