Python – Google app engine and python and objects that pass by value

google-app-enginepython

This is really a python language question, but its wrapped around a Google appengine specific problem.

We have

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

Because the user account is accessed so often, we keep a copy in session using gaeutilities (as a bonus question, is this bad on GAE? I thought I'd relieve the db a bit.)

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
    #######

What is happening in each of these 3 cases? Why don't cases 1 and 2 work?

Best Answer

I'm guessing:

Putting objects in the Session means that the objects is serialized ( pickled usually ) and stored somewhere (disk, memory, db). When it is retrieved from the Session, a new object is created from serialized the old state.

  • In the first example each self.session[ 'current_user' ] gives you a new object, one of which you update and the other is saved to the db.
  • In the 2nd you get one object, save it to the DB but not in the session.

Btw, Python does "call by sharing", but that has nothing to do with your problem ;-)