Python 在SQLAlchemy模型中使用_插槽

Python 在SQLAlchemy模型中使用_插槽,python,sqlalchemy,slots,Python,Sqlalchemy,Slots,我在我的新项目中使用了SQLAlchemy,并且希望在模型中使用\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu(在没有alchemy的beta版本中,\uuuuuuuuuuuuuuuu。但我无法将它们与SQLAlchemy声明结合起来,并在代码中出现以下错误: from sqlalchemy.ext.declarative import declarative_base Base = declarative_base

我在我的新项目中使用了SQLAlchemy,并且希望在模型中使用
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
(在没有alchemy的beta版本中,
\uuuuuuuuuuuuuuuu。但我无法将它们与SQLAlchemy声明结合起来,并在代码中出现以下错误:

from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()

class NotWorking(Base):
     __tablename__ = 'table1'
     pk = Column(Integer, primary_key=True)
     name = Text(length=64, convert_unicode=True)

     __slots__ = ['name', 'pk']
错误

ValueError.\uuuuu插槽中的“name”与类变量冲突

这应该是
\uuuuuuu slots\uuuuuuu
修改类来为其中定义的字段创建描述符,因此一种解决方法是使隐藏字段(\u name)和模型字段作为属性,如下所示:

class Working(Base):
    __tablename__ = 'table2'
    pk = Column(Integer, primary_key=True)
    name = Text(length=64, convert_unicode=True)

    __slots__ = ['_name', '_pk']

     # Workaround
    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        self._name = name

但这段代码编写起来可能有点乏味,您需要为每个新字段添加相应的属性。我想知道,在仍然使用声明性基(不使用经典映射)的情况下,有没有更好的方法可以不使用属性。

您可以在类主体上使用简单的Python语句,根据
\uuuu slots\uu
属性本身自动创建简单属性:

class Working(Base):
    ...

    __slots__ = ['_name', '_pk']

    for _tmp_name in __slots__:
        locals()[_tmp_name[1:]] = property(lambda self, name=_tmp_name: getattr(self, name))
    del _tmp_name
请注意,虽然在函数或方法中返回y
locals
的字典有些特殊,对它的修改不会影响实际变量,但它在类主体本身中起到普通字典的作用

如果您有多个模型,或者觉得它太粗糙,那么可以将其放入元类或
\uuu init\u子类\uuu
方法中(Python 3.6+):

对于元类(python<3.6),只需在元类
\uuuu init\uuuu
中放置相同的三行代码即可:

class MetaBase(type):
    def __init__(cls, name, bases, namespace):
         super().__init__(name, bases, namespace)
         for name in cls.__slots__:
             setattr(cls, name[1:], property(lambda self, name=name: getattr(self, name)))


class Working(Base, metaclass=MetaBase):
    ...

语句
name=Text(length=64,convert\u unicode=True)
是否已经创建了正确的描述符?所以您需要
\uuuuuu slots\uuuu=()
来表示不需要存储额外的实例变量?
\uuuuuuu slots\uuuuu
旨在减少内存消耗,并可能使对象更为静态,但(我发现在检查注释后)由于Base没有定义它们,所以它们并不是非常有用<代码>\uuuu dict\uuuu
仍然保留,并且您仍然可以添加新字段,因此它们最多只能用作指南。
class MetaBase(type):
    def __init__(cls, name, bases, namespace):
         super().__init__(name, bases, namespace)
         for name in cls.__slots__:
             setattr(cls, name[1:], property(lambda self, name=name: getattr(self, name)))


class Working(Base, metaclass=MetaBase):
    ...