Что означает, что объект «Пользователь» не повторяется? - PullRequest
0 голосов
/ 25 февраля 2012

После ответа на один из моих вопросов об алгоритме обхода дерева

Количество нижестоящих распределений MLM

Я хочу пройтись по всему дереву пользователей и распечатать узлы, но получаю странное сообщение об ошибке:

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 ]

3 голосов
/ 25 февраля 2012

Строка

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

ожидает, что RHS вернет список для расширения 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 голос
/ 26 февраля 2012

Почему бы не два вложенных в?

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()))
0 голосов
/ 25 февраля 2012

Позвольте мне уточнить, пройдя по строке кода строка за строкой:

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

КакВы можете видеть, что это печатает идентификатор каждого человека в дереве запросов (кроме корневого идентификатора, 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
...