1

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

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

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' object does not support indexing

对索引有什么建议吗?

4

2 回答 2

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

Note: the add_to_memcache function is intended to be shared in more than one class, but I have put it inside Book for asking only.

于 2013-05-24T08:11:01.920 回答
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]
于 2013-05-23T15:01:52.293 回答