SQLAlchemy commit changes to object modified through __dict__

后端 未结 2 1954
旧巷少年郎
旧巷少年郎 2020-11-30 10:47

I am developing a multiplayer game. When I use an object from inventory, it should update the user creature\'s stats with the values of the attributes of an object.

相关标签:
2条回答
  • 2020-11-30 10:58

    Don't use __dict__. Use getattr and setattr to modify attributes by name:

    for attribute in obj.attributes:
        setattr(cur_creature,str(attribute.Name), getattr(cur_creature,str(attribute.Name)) + attribute.Value)
    

    More info:

    setattr

    getattr

    0 讨论(0)
  • 2020-11-30 11:11

    The problem does not reside in SQLAlchemy but is due to Python's descriptors mechanism. Every Column attribute is a descriptor: this is how SQLAlchemy 'hooks' the attribute retrieval and modification to produce database requests.

    Let's try with a simpler example:

    class Desc(object):
        def __get__(self, obj, type=None):
            print '__get__'
        def __set__(self, obj, value):
            print '__set__'
    
    class A(object):
        desc = Desc()
    
    a = A()
    a.desc                  # prints '__get__'
    a.desc = 2              # prints '__set__'
    

    However, if you go through a instance dictionary and set another value for 'desc', you bypass the descriptor protocol (see Invoking Descriptors):

    a.__dict__['desc'] = 0  # Does not print anything !
    

    Here, we just created a new instance attribute called 'desc' with a value of 0. The Desc.__set__ method was never called, and in your case SQLAlchemy wouldn't get a chance to 'catch' the assignment.

    The solution is to use setattr, which is exactly equivalent to writing a.desc:

    setattr(a, 'desc', 1)   # Prints '__set__'
    
    0 讨论(0)
提交回复
热议问题