如何对类实例列表进行排序

时间:2013-05-23 14:44:49

标签: python google-app-engine memcached

我正在使用GAE和memcache。对于我的书籍列表,我创建了一个密钥并将其存储在memcache中,以便每次都必须查看列表时避免使用命中数据库。

当我向数据库添加一个新项目时,我也将它添加到memcache键,但是列表的开头,就像这样(在这种情况下,self是书本实体):

class Book(ndb.Model):
    """ A Book """
    title = ndb.StringProperty(required=True)
    author = ndb.StringProperty(required=True)

    # Add a new element to memcache
    def add_to_memcache(self):
        data = memcache.get('mybooks')
        if data:
            logging.info('Adding to Memcache for key %s.', 'mybooks')
            data.insert(0, self)
            if not memcache.set('mybooks', data):
                logging.error('Memcache set failed for key %s.', 'mybooks')

    @classmethod
    def get_all(cls):
        key = 'mybooks'
        books = memcache.get(key)
        if books is None:
            books = list(Book.query().order(Book.title).fetch(100))
            if not memcache.set(key, books):
                logging.error('Memcache set failed for key %s.', key)
        else:
            logging.info('Memcache hit for key %s.', key)
        return books

    @classmethod
    def save(cls, **kwargs):
        book = cls(title=kwargs['title'],
                author=kwargs['author']
                )
        book.put()
        # Modify memcache for this key
        book.add_to_memcache()
        return book

所以,在第一次阅读memcache时,所有内容都是有序的,但是有了一本新书,这个列表就不再订购了。

我试图制作:

data.insert(0, self)
data = sorted(data, key=itemgetter(1))

但我收到错误 TypeError:'Book'对象不支持索引

有关索引的任何建议吗?

2 个答案:

答案 0 :(得分:1)

这里问题的最终解决方案可能对其他一些"堆栈器"有用。 关键是行

data = sorted(data, key=lambda self: self.key_func())

将从数据列表中获取每个项目(使用lambda函数)并调用key_func,它将评估对象类型以按右侧字段排序。 感谢@root提供此解决方案。

class Book(ndb.Model):
    """ A Book """
    title = ndb.StringProperty(required=True)
    author = ndb.StringProperty(required=True)

    def key_func(obj):
            if isinstance(obj, Book):
                return obj.title
            else:
                raise TypeError('Unknown object!!!')

    # Add a new element to memcache
    def add_to_memcache(self):
        data = memcache.get('mybooks')
        if data:
            logging.info('Adding to Memcache for key %s.', 'mybooks')
            data.insert(0, self)
            data = sorted(data, key=lambda self: self.key_func())
            if not memcache.set('mybooks', data):
                logging.error('Memcache set failed for key %s.', 'mybooks')

    @classmethod
    def get_all(cls):
        key = 'mybooks'
        books = memcache.get(key)
        if books is None:
            books = list(Book.query().order(Book.title).fetch(100))
            if not memcache.set(key, books):
                logging.error('Memcache set failed for key %s.', key)
        else:
            logging.info('Memcache hit for key %s.', key)
        return books

    @classmethod
    def save(cls, **kwargs):
        book = cls(title=kwargs['title'],
                author=kwargs['author']
                )
        book.put()
        # Modify memcache for this key
        book.add_to_memcache()
        return book

注意:add_to_memcache函数旨在在多个类中共享,但我已将其放在Book中仅供查询。

答案 1 :(得分:0)

免责声明:我对GAE了解不多,所以这个答案纯粹是关于排序。


首先,如果没有实现operator.itemgetter方法,则无法直接使用__getitem__访问类属性,因为类基本上是字典 - 所以它的属性不是有序的。

示例:

In [1]: from random import shuffle

In [2]: from operator import itemgetter

In [3]: rand = range(10)

In [4]: shuffle(rand)

In [5]: rand
Out[5]: [1, 9, 2, 5, 4, 3, 0, 6, 8, 7]

In [6]: class A(object):
   ...:     def __init__(self, n):
   ...:         self.n = n
   ...:     def __repr__(self):
   ...:         return str(self.n)
   ...:     

In [7]: sorted([A(n) for n in rand], key=itemgetter(0))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-7-33ca678e282d> in <module>()
----> 1 sorted([A(n) for n in rand], key=itemgetter(0))

TypeError: 'A' object does not support indexing

In [8]: class A(object):
   ...:     def __init__(self, n):
   ...:         self.n = n
   ...:     def __repr__(self):
   ...:         return str(self.n)
   ...:     def __getitem__(self,ind):
   ...:         return self.n
   ...:     

In [9]: sorted([A(n) for n in rand], key=itemgetter(0))
Out[9]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

但也许你有更好的选择:

您可以使用operator.attrgetter;对于Book个实例(按标题排序),这将是:

sorted(data, operator.attrgetter('title'))

您可以编写更通用的键功能进行排序:

def key_func(obj):
    if isinstance(obj, Book):
        return obj.title
    elif isinstance(obj, SomeOtherClass):
        return obj.some_other_attr
    else:
        raise TypeError('Unknown object!!!')

#  usage: sorted(data, key=key_func)

或者您可以为每个类实现__cmp__方法,因此排序可以在没有的情况下工作  关键功能:

def __cmp__(self, other):
    return cmp(self.attribute_you_want_to_be_compared, other)

示例:

In [10]: class A(object):
    ...:     def __init__(self, n):
    ...:         self.n = n
    ...:     def __repr__(self):
    ...:         return str(self.n)
    ...:     def __cmp__(self, other):
    ...:         return cmp(self.n, other)
    ...:     

In [11]: sorted([A(n) for n in rand])
Out[11]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]