谷歌应用引擎、Python和按值传递的对象

2 投票
3 回答
656 浏览
提问于 2025-04-15 14:26

这其实是一个关于Python语言的问题,但它涉及到一个特定于Google App Engine的问题。

我们有

class User( db.Model ) :
  email = db.StringProperty()
  name = db.StringProperty()
  password = db.StringProperty()
  # more fields..

因为用户账户被频繁访问,我们使用gaeutilities在会话中保留了一份副本(作为额外的问题,这样在GAE上是否不好? 我想这样可以减轻数据库的负担。)

class UpdateProfile( webapp.RequestHandler ):
  def post( self ):
    # User posting update to his name
    self.session = sessions.Session()

    #######
    # way#1: update the copy of the User object in SESSION, then .put() it
    self.session[ 'current_user' ].name = self.request.get( 'name' )
    self.session[ 'current_user' ].put()
    # does not work.
    #######

    #######
    # way#2: make a copy of the User object in SESSION, then .put() it
    user = self.session[ 'current_user' ]
    user.name = self.request.get( 'name' )
    user.put()
    # works to update the datastore, but the copy of user in self.session
    # is NOT UPDATED!  I thought Python was
    # pass-by-reference.  It is when you work with lists anyway.
    # Why isn't it "acting right" with this type of object??
    #######


    #######
    # way#3: way that works.
    user = self.session[ 'current_user' ]
    user.name = self.request.get( 'name' )
    user.put()
    self.session[ 'current_user' ] = user
    # works completely
    #######

这三种情况各自发生了什么?为什么情况1和2不工作?

3 个回答

2

我是gaeutilities的作者。我联系了Nick来讨论这个问题,他给了我一些很好的建议。在最终的1.3版本中,我会有一个解决方案。

3

我猜:

把对象放进会话(Session)里,意味着这些对象会被序列化(通常是用一种叫做“腌制”的方式),然后存储在某个地方(比如磁盘、内存或者数据库)。当你从会话中取出这些对象时,会根据之前保存的状态创建一个新的对象。

  • 在第一个例子中,每次使用 self.session[ 'current_user' ] 都会得到一个新的对象,其中一个对象会被更新,另一个则会被保存到数据库。
  • 在第二个例子中,你得到一个对象,把它保存到数据库,但不保存在会话里。

顺便提一下,Python 是“共享调用”的方式,但这和你的问题没有关系;-)

1

抱歉,我是这个网站的新手,不知道在哪里可以对答案进行评论?

不过,我已经解决了最初发帖时提到的具体问题。虽然数据的序列化(就是把数据转换成可以存储或传输的格式)还是不太理想,发生在写入的时候,但我确保在会话中将模型实体作为项目分配时能够正常工作。我没有选择重写序列化(这会是一个大工程),而是决定在将模型插入会话数据时进行检测,并为它设置一个引用属性。这意味着模型对象根本不需要经历序列化的过程。

如果与引用属性关联的实体被删除,当你尝试加载它时,会话中的引用属性也会被删除。这就意味着你需要处理一些异常,比如会话抛出的KeyError,就像处理字典一样。我希望这个解释足够直观,但我也欢迎任何评论。我会在接下来的几周内多次查看这个页面。

撰写回答