New to Python, but I have been researching this for a couple hours. Forgive me if I missed something obvious.
I have a class called LineItem, which has an attribute _lineItems, a list of LineItems that belong to the given LineItem. A sub-list, basically.
I want to print out a LineItem and all of its sub-items (and the sub-items own sub-items), but I'm having trouble with the iteration.
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)
An example LineItem that's giving me the trouble is defined below as ext2, with three children.
# 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])
I have this recursive function for iterating all the sub-items (and printing them numbered, like 1, 2, 2.1 as the first subitem of the second item, etc)
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
but when I try to use it
def main():
print_line_item([ext1, ext2, ext3]) #ext1 has no children, prints fine
if __name__=="__main__":
main()
I get
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
Okay, so somehow I'm screwing up lists.
if I add a couple print statements:
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
I get proof that a._lineItems is indeed a list, printed as follows:
[<__main__.LineItem object at 0x0227C430>, <__main__.LineItem object at 0x0227C5F0>, <__main__.LineItem object at 0x0227C670>]
and that the b I'm trying to pass to the recursing call is a memory address of a single LineItem
<__main__.LineItem object at 0x0227C430>
Sooo how am I actually supposed to do what I'm trying to do? I tried a couple things with .iter or ___iter___
but no luck.
Also, the if a._lineItems != [] doesn't seem to be working either (nor variations on that). I get printed lines of "None"
It makes sense you're getting a not-iterable message--you're essentially recursing into print_line_item for each item in a list--and sooner or later, you'll hit something in a list that isn't iterable itself--and you just go on and call print_line_item() on it, which will try to iterate over it.
If you want to ask "is this item a list?" you could use
isinstance(some-object, list)
. Or, if you want to allow for other iterable-but-not-list-things, you can useif isinstance(some-object, collections.Iterable)
(you'll have to import collections).It might be correct version, not tested.