python - 字典 : new entity taking old property? 的 GAE NDB PickleProperty

标签 python google-app-engine google-cloud-datastore pickle app-engine-ndb

对我来说看起来像是一个错误,但也许有人会对此有一个合理的解释。 考虑以下代码:

class Test(ndb.Model):
    a= ndb.IntegerProperty()
    p = ndb.PickleProperty(default={})

现在执行以下操作:

>> t1 = Test()
>> t1.p['a'] = 1
>> t1.p['b'] = 2
{'a': 1, 'b': 2}

到目前为止,一切都很好。但现在:

>> t2 = Test()
>> t2.p
{'a': 1, 'b': 2}

全新的 t2 实例已被分配 t1 的 p 值?!!

除了错误之外还有什么解释吗? 请注意,对 t1 执行 put() 操作不会改变行为。

最佳答案

在 Python 中,默认参数被评估一次——因此您使用的是单个 dict(您的 default={ } 是每个进程的一个字典,而不是每个实体一个!)跨越所有 Test 类型的实体,这些实体恰好位于同一进程内,并且 p 未明确设置。

如果你这样做t=Test(p={}),那么t就可以了,有自己的dict。如果您执行t=Test(),然后t.p = {},您也会没事的。但是,如果您不以某种方式设置实体的特定 p,它将使用与该实体的所有实体使用的相同的默认 dict类型,在同一进程内,没有显式设置 p

当您放置一个Test实体时,进入数据存储的是其p当时的 pickle “快照”——当您取回它时,它将恢复到该状态,并且现在与default single-dict-per的其他可能使用断开连接-过程。但这些只是这种可疑用法中的更多异常现象。

简单地说,可变默认值在 Python 中并不是一个好主意——人们几乎从来没有正确使用过它们。这适用于对ndb.PickleProperty的调用,至少与对其他Python可调用对象的任何其他调用一样!

添加:如果您需要一个 PickleProperty 来专门保存一个字典,并且发现每次实例化此类实体时显式添加 p={} 太麻烦,子类化 PickleProperty 可能会有所帮助。即:

class DictPickleProperty(ndb.PickleProperty):
    def __init__(self, **kwds):
        kwds['default'] = kwds.get('default', {})
        super(DictPickleProperty, self).__init__(**kwds)

如果 default 未指定 (A) 或 (B) 指定为不是 dict 的内容,您想要执行的操作当然取决于您。这个简单的例子在情况(B)中没有做任何特别的事情——(所以例如 default=[] 仍然会导致问题)——但确实使用了一个新的空 dict 以防万一(一)。

或者,您可以尝试将任何提供的 default 值转换为新的 dict(因此 []{} 会创建一个新的空 dict,但许多其他值会引发异常):

        kwds['default'] = dict(kwds.get('default', ()))

或者,当然,还有许多其他变体。

关于python - 字典 : new entity taking old property? 的 GAE NDB PickleProperty,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28387723/

相关文章:

google-app-engine - 按列表对象化查询过滤器?

java - 如何在 Eclipse for Google App Engine 中从 Java 7 切换到 Java 6?

php - PHP 中来自 Appengine 的带有基本身份验证的 POST 请求

google-app-engine - 我可以比较 GAE 的 ndb 中单一类型的两个属性吗?

python - 方法与属性哪个更快?

python - Pandas 从上一行中减去另一列中的值

python - eval 函数的第二个参数与第三个参数有何不同?

python ,scipy -- 如何返回概率介于两个值之间的值

python - Eclipse+PyDev+GAE 内存缓存 "Undefined variable from import: get"

google-app-engine - 转到 Google 数据存储空值