首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >__slots__与SQLAlchemy模型的结合

__slots__与SQLAlchemy模型的结合
EN

Stack Overflow用户
提问于 2017-03-27 15:04:26
回答 1查看 1K关注 0票数 4

我在我的新项目中使用SQLAlchemy,并且希望在模型中使用__slots__ (在beta版本中没有炼金术,__slots__是必要的,因为创建了大量的对象)。但是,我无法将它们与SQLAlchemy声明组合在一起,并获得以下代码错误:

代码语言:javascript
复制
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: 'name' in __slots__ conflicts with class variable

它被期望为__slots__修改类来为其中定义的字段创建描述符,因此一种解决方法是使隐藏字段(_name)和使模型字段充当属性,如下所示:

代码语言:javascript
复制
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

但是这段代码编写起来有些繁琐,您需要为每个新字段添加相应的属性。我想知道,是否有更好的方法可以不使用属性,同时仍然使用声明基(不使用经典映射)。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-03-27 15:22:51

您可以使用类主体上的简单Python语句来根据__slots__属性本身自动创建简单属性:

代码语言:javascript
复制
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的字典有些特殊,其中对它的修改不影响实际变量,但它作为类主体本身中的普通字典工作。

如果您有几个模型,或者发现这太麻烦了,也可以将其放在元类或__init_subclass__方法中(Python ):

代码语言:javascript
复制
class MyBase(Base):
    def __init_subclass__(cls, *args, **kwargs):
        for name in cls.__slots__:
            setattr(cls, name[1:], property(lambda self, name=name: getattr(self, name)))

class Working(MyBase):
    ...

对于元类情况(python < 3.6),只需在元类__init__中放置相同的三行

代码语言:javascript
复制
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):
    ...
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43049979

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档