“用户”对象不可迭代是什么意思?

时间:2012-02-25 14:35:23

标签: python google-app-engine tree google-cloud-datastore

回答我对树行走算法的一个问题

MLM downline distribution count

我想遍历整个用户树并打印节点,但我收到一条奇怪的错误消息:

TypeError: 'User' object is not iterable

这是我试图在树上行走的代码:

    downlinestack = []
    distributor=self
    downlinestack += User.query(User.sponsor == distributor.key).fetch(99999999)
    while downlinestack:
        downline = downlinestack.pop()
        logging.info('downline: %s' %str(downline))
        for person in downline:
            downlinestack.append(User.query(User.sponsor == person.key).fetch(99999999))
            logging.info('person: %s' %str(person.key.id()))

我应该如何更改代码,以便它通过赞助商属性遍历用户树?

谢谢

更新

我发现了一个递归解决方案,它看起来像这样:

def downline(self, person, team, teamlist):
    firstline = User.query(User.sponsor == person.key).fetch(99999999)
    if firstline:
        for person in firstline:
            teamlist.append(person)
            newdownline = self.downline(person, team, teamlist)        
            team.append(newdownline)
    return teamlist           

def this_month_non_manager_silver(self):
    silver = 0
    today = date.today()
    timeline = date(today.year, today.month, 1)
    for person in self.downline(self, [], []):
        logging.info('element:%s' % str(person.key.id()) )
        orders = model.Order.all().filter('distributor_id =',
                    person.key.id()).filter('created >',
                    timeline).filter('status =', 'PAID'
                    ).fetch(999999)
        for order in orders:
            for (idx, item) in enumerate(order.items):
                purchase = model.Item.get_by_id(long(item.id()))
                amount = int(order.amounts[idx])
                silver = silver + amount * purchase.silver \
                        / 1000.000            
    return silver

3 个答案:

答案 0 :(得分:3)

该行

downlinestack += User.query(User.sponsor == distributor.key).fetch(99999999)

希望RHS返回一个列表以使用。{/ p>扩展downlinestack

>>> a = ['a']
>>> a += ['b']
>>> a
['a', 'b']

除非User.query()。fetch()返回一个列表,否则我怀疑你的意思是

downlinstack.append(downlinestack += User.query(User.sponsor == distributor.key).fetch(99999999))

我的另一个猜测是,无论你追加downlinestack的是什么都不可迭代,所以下面的行失败了

for person in downline:

答案 1 :(得分:1)

为什么不只是两个嵌套的?

for downline in User.query(User.sponsor == distributor.key).fetch(99999999):
    logging.info('downline: %s' %str(downline))
    for person in downline:
        downlinestack.append(User.query(User.sponsor == person.key).fetch(99999999))
        logging.info('person: %s' %str(person.key.id()))

答案 2 :(得分:0)

让我通过逐行浏览代码来澄清:

downlinestack = []
distributor=self
downlinestack += User.query(User.sponsor == distributor.key).fetch(99999999)

首先,您没有告诉我们User.query返回的内容。我假设它是一个用户对象列表。现在downlinestack看起来像这样:[User1, User2, User3]

while downlinestack:
    downline = downlinestack.pop()

现在downline包含从堆栈末尾弹出的单个用户User3

    logging.info('downline: %s' %str(downline))
    for person in downline:

这是您的错误:User3 不可迭代。没有什么神秘之处:它不是那种对象。它不是可以依次迭代访问的项目集合。如果你想在这里迭代一些东西,你必须自己生成可迭代的

有两种方法可以做到这一点。第一种是迭代User.query返回的列表:

distributor=self
downlinestack = User.query(User.sponsor == distributor.key).fetch(99999999)
while downlinestack:
    top_person = downlinestack.pop()
    logging.info('top_person: %s' %str(top_person))
    for person in User.query(User.sponsor == top_person.key).fetch(99999999):
        downlinestack.append(person)

您的另一个选择是将downlinestack放入列表列表中:

distributor=self
downlinestack = [User.query(User.sponsor == distributor.key).fetch(99999999)]
while downlinestack:
    downline_top = downlinestack.pop()
    for person in downline_top:
        downlinestack.append(User.query(User.sponsor == person.key).fetch(99999999))
        logging.info('person: %s' %str(person.key.id()))

其中任何一个都应该有用。

我没有足够的上下文来测试上面的内容,但我创建了自己的简化测试方案,只是为了说明这确实有效。

>>> query_tree = {0: [1, 2, 3], 1: [4, 5], 2: [6], 3: [7, 8, 9, 10], 4: [], 
                  5: [11, 12], 6: [], 7: [], 8: [13], 9: [], 10: [], 11: [14], 
                  12: [], 13: [], 14: []}
>>> stack = query_tree[0][:]   #make a copy to avoid changes to `query_tree`
>>> while stack:
...     top_person = stack.pop()
...     print top_person
...     for person in query_tree[top_person]:
...         stack.append(person)
... 
3
10
9
8
13
7
2
6
1
5
12
11
14
4

正如您所看到的,这会在查询树中打印出每个人的id(root id为0除外)。

然后是另一种方法:

>>> stack = [query_tree[0]]
>>> while stack:
...     top_person_list = stack.pop()
...     for person in top_person_list:
...         print person
...         stack.append(query_tree[person])
... 
1
2
3
7
8
9
10
13
6
4
5
11
12
14