开发者

Idiomatic List Wrapper

开发者 https://www.devze.com 2023-02-13 14:14 出处:网络
In Google App Engine, I make lists of referenced properties much like this: class Referenced(BaseModel):

In Google App Engine, I make lists of referenced properties much like this:

class Referenced(BaseModel):
    name = db.StringProperty()

class Thing(BaseModel):
    foo_keys = db.ListProperty(db.Key)

    def __getattr__(self, attrname):
        if att开发者_如何学Pythonrname == 'foos':
            return Referenced.get(self.foo_keys)
        else:
            return BaseModel.__getattr__(self, attrname)

This way, someone can have a Thing and say thing.foos and get something legitimate out of it. The problem comes when somebody says thing.foos.append(x). This will not save the added property because the underlying list of keys remains unchanged. So I quickly wrote this solution to make it easy to append keys to a list:

class KeyBackedList(list):
    def __init__(self, key_class, key_list):
        list.__init__(self, key_class.get(key_list))
        self.key_class = key_class
        self.key_list = key_list

    def append(self, value):
        self.key_list.append(value.key())
        list.append(self, value)

class Thing(BaseModel):
    foo_keys = db.ListProperty(db.Key)

    def __getattr__(self, attrname):
        if attrname == 'foos':
            return KeyBackedList(Thing, self.foo_keys)
        else:
            return BaseModel.__getattr__(self, attrname)

This is great for proof-of-concept, in that it works exactly as expected when calling append. However, I would never give this to other people, since they might mutate the list in other ways (thing[1:9] = whatevs or thing.sort()). Sure, I could go define all the __setslice__ and whatnot, but that seems to leave me open for obnoxious bugs. However, that is the best solution I can come up with.

Is there a better way to do what I am trying to do (something in the Python library perhaps)? Or am I going about this the wrong way and trying to make things too smooth?


If you want to modify things like this, you shouldn't be changing __getattr__ on the model; instead, you should write a custom Property class.

As you've observed, though, creating a workable 'ReferenceListProperty' is difficult and involved, and there are many subtle edge cases. I would recommend sticking with the list of keys, and fetching the referenced entities in your code when needed.

0

精彩评论

暂无评论...
验证码 换一张
取 消