使用只读列获取相同值的只读属性

Mar*_*nen 8 python sqlalchemy python-3.x

游戏引擎为我提供了一个Player具有uniqueid只读属性的类来识别玩家.我想将其"转换"为SQLAlchemy,Column以便我可以像这样查询玩家:

query = session.query(Player).filter(Player.uniqueid=='STEAM_0:0:1234567')
player = query.one_or_none()
if player is None:
    player = Player(uniqueid='STEAM_0:0:1234567')
Run Code Online (Sandbox Code Playgroud)

这是我班级目​​前的样子:

class Player(game.Player, db.Model):
    _uniqueid = Column('uniqueid', String(21), unique=True, nullable=False)

    def __init__(self, index, **kwargs):
        game.Player.__init__(index)  # initializes uniqueid
        db.Model.__init__(_uniqueid=self.uniqueid, **kwargs)
Run Code Online (Sandbox Code Playgroud)

接下来我想为它创建一个只读接口_uniqueid,因此API用户不能再写入变量(好吧,他们可以通过_uniqueid,但这是他们的责任,因为访问它应该通过非私有uniqueid).

我想uniqueid用一个新原件覆盖原件:

@property
def uniqueid(self):
    return self._uniqueid
Run Code Online (Sandbox Code Playgroud)

这是只读的并且"隐藏"原件_uniqueid,阻止任何人写入它,除非他们故意访问私有(我甚至不会在文档中列出它,我只会暴露非私有的).

唯一的问题是,这完全取代旧的,这意味着由于使用新的吸气剂而不是旧的吸气剂,我__init__的功能_uniqueid=self.uniqueid无法self.uniqueid使用.

总而言之,我想要的是将只读属性转换为可用于使用SQLAlchemy查询的只读属性.这是可能的,如果,如何?

uni*_*rio 1

您可以使用super来访问 的属性game.Player。我们可以使用 Cython 创建的简单 C 扩展类型进行测试:

# game.pyx
cdef class Player:
    cdef int index;

    def __init__(self, index):
        self.index = index

    @property
    def uniqueid(self):
        return "foo"


# test.py
class Player(game.Player, Base):
    __tablename__ = "player"

    id = Column(Integer, primary_key=True)
    _uniqueid = Column('uniqueid', String(21), unique=True, nullable=False)

    def __init__(self, index, **kwargs):
        game.Player.__init__(self, index)  # initializes uniqueid
        Base.__init__(self, _uniqueid=super().uniqueid, **kwargs)

    @property
    def uniqueid(self):
        return self._uniqueid

print(Player(1).uniqueid)  # "foo"
Run Code Online (Sandbox Code Playgroud)

由于从 C 扩展类型继承的不确定性,这可能会也可能不会起作用,具体取决于类型game.Player使用的 C 魔法。

另外,由于 ORM__init__在从数据库加载实例时会绕过,因此您必须挂钩该load事件才能初始化game.Player类型。