2017-03-27 16 views
2

새 프로젝트에서 SQLAlchemy를 사용 중이고 __slots__을 모델과 함께 사용하고 싶습니다. (베타 버전에서는 연금술없이 많은 수의 개체가 만들어 졌으므로 __slots__이 필요했습니다). 하지만 코드에 대해 다음과 같은 오류가 SQLAlchemy의 선언으로 그들을 결합하여 얻을 수 없습니다입니다 :SQLAlchemy 모델에서 __slots__ 사용하기

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'] 

오류 그들에 정의 된 필드에 대한 설명을 만들 클래스를 수정 __slots__로 예상된다

ValueError: 'name' in __slots__ conflicts with class variable

한 가지 해결 방법은 숨겨진 필드 (_name)를 만들고 모델 필드를 다음과 같이 속성으로 사용하는 것입니다.

그러나이 코드는 작성하는 것이 약간 지루할 수 있으며 각 새 필드에 해당 속성을 추가해야합니다. 나는 궁금한 점이 있는데, 선언적 기반을 사용하면서 (Classical Mappings을 사용하지 않고) 속성없이 할 수있는 더 좋은 방법이있다. 사전 함수 또는 메소드 내에서 Y locals을 반환하면서이라고

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 

주 : __slots__ 속성 자체를 기반으로 단순 속성의 생성을 자동화 할 클래스 본문에 간단한 파이썬 문을 사용할 수 있습니다

+0

하지 문 '이름 = 텍스트 (길이 = 64, convert_unicode = TRUE)는'이미 올바른 설명을 만들 수 있습니까? 그래서 저장 될 필요가있는 여분의 인스턴스 변수가 없다는 것을 나타 내기 위해'__slots__ =()'을 가지고 있겠는가? –

+0

'__slots__'는 메모리 사용량을 줄이기위한 것이지, 객체를 조금 더 정적으로 만들었지 만, Base가 정의하지 않았기 때문에 주석을 확인한 후에 발견되었습니다. 정확하게 유용하지는 않습니다. '__dict__'는 여전히 남아 있으며, 새로운 필드를 추가 할 수 있으므로 대부분 지침으로 만 사용할 수 있습니다. – jOOsko

답변

1

다소 특수하며,이 변수를 수정하면 실제 변수에 영향을 미치지 않으므로 클래스 본문 자체에서 일반 사전으로 작동합니다.

여러 모델을 가지고, 너무 해키이를 발견하면

, 그것은 메타 클래스 또는 __init_subclass__ 방법뿐만 아니라 (파이썬 3.6)에 넣어 수 있습니다 : 메타 클래스의 경우를 들어

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): 
    ... 

(파이썬 < 3.6) 단지 __init__ 메타 클래스에서 같은 세 줄을 넣어 :

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): 
    ...