0

With python and 'type()', I need to reproduce this 'structure', but dynamically:

class Class1(BaseClass):

    def items(self):
        return [
                'abc',
                'def',
                'hij'
                ]

    def location(self, obj):
        return obj


class Class2(BaseClass):

    def items(self):
        return [
                'klm',
                'nop',
                'qrs'
                ]

    def location(self, obj):
        return obj


final_dict = {
    'Class1': Class1,
    'Class2': Class2,
}

Here's what I came up with:

def get_final_dict():
    list1 = ['abc', 'def', 'hij']
    list2 = ['klm', 'nop', 'qrs']
    final_dict = {}
    final_dict.update({'Class1': type("Class1", (BaseClass,), {"items": lambda self: list1, "location": lambda self, obj: obj})})
    final_dict.update({'Class2': type("Class2", (BaseClass,), {"items": lambda self: list2, "location": lambda self, obj: obj})})
    return final_dict

final_dict = get_final_dict()

Note that I didn't include the 'lists' as part of the lambda, as these are dynamically generated from a method in my 'real life' situation.

This works with this 'prototype', but apparently doesn't work with my 'real life scenario'.

Here's what I'm trying to do with Django's sitemap and 'django-static-sitemaps':

def get_sitemaps_dicts():

    nb_of_items_sql = 'SELECT count(id) FROM table'
    cursor = connection.cursor()
    cursor.execute(nb_of_items_sql)
    nb_of_items = cursor.fetchone()[0]

    if nb_of_items < 50000:
        nb_of_items = 50000

    all_classes = {}
    for i in range(nb_of_items / 50000):
        print 'item #' + str(i * 50000)

        sql = 'SELECT url FROM table ' \
              'LIMIT 50000 OFFSET %s'

        cursor.execute(sql, [i * 50000])
        items = cursor.fetchall()
        all_items = []
        for item in items:
            all_items.append(item[0])

        all_classes.update({'Items' + str(i): type("Items" + str(i), (Sitemap,), {"items": lambda self: all_items, "location": lambda self, obj: obj})})

    return all_classes

When I set 'sitemaps=get_sitemaps_dicts()', I get all the sitemaps but they are all empty (no URL at all). But, if I set it to my 'prototype', the sitemaps are generated correctly with the URLs.

The reason I'm doing this 'dynamic list' is because the static sitemap plugin will iterate over all the collection for each group of 50k items. When you have 4+ millions rows, it gets a bit long to generate.

mrmuggles
  • 2,081
  • 4
  • 25
  • 44
  • The code you posted **works**. Your actual situation is clearly different from this MCVE, please update to one that actually illustrates your issue. – Martijn Pieters Oct 20 '15 at 09:40
  • To be precise: `final_dict['Class1']().items()` and `final_dict['Class2']().items()` return the expected lists, and `final_dict['Class1']().location('foo')` and `final_dict['Class2']().location('foo')` return `'foo'`, as expected. – Martijn Pieters Oct 20 '15 at 09:41
  • Thanks, I added my 'real world scenario' – mrmuggles Oct 20 '15 at 11:10
  • `all_items` is a closure here and will reflect the last query results. See the duplicate; bind the data to your lambda or the class itself. – Martijn Pieters Oct 20 '15 at 11:20
  • Doesn't seems like I can make it work with the 'example'. How can I bind the data to the class since I need to create the list in a loop anyway? – mrmuggles Oct 20 '15 at 11:36
  • 1
    You could use `lambda self, items=all_items: items`. This binds the `all_items` list to a default argument. – Martijn Pieters Oct 20 '15 at 11:43
  • It seems to work. Thanks! – mrmuggles Oct 20 '15 at 16:49

0 Answers0