2017-12-27 26 views
0

나는 __slots__이 무엇을하는지, 그리고 무엇을 사용해야하는지 알고 있습니다.__slot__ 설명자는 어떻게 파이썬에서 작동합니까?

그러나 __slots__을 사용하여 생성 된 member 설명 자의 기본 메커니즘이 어떻게 작동하는지에 대한 포괄적 인 답을 찾지 못했습니다.

실제로 저장된 오브젝트 레벨 값은 어디에 있습니까?

설명자에 대한 직접적인 속성 액세스없이이 값을 변경할 수있는 방법이 있습니까?
(예. 클래스 C__dict__이있는 경우 대신 C.keyC.__dict__['key'] 할 수있는) 하나가 유사한 클래스 수준의 설명을 작성하여 정의하는 객체 __slots__의 불변성을 "확장"할 수

를? 그리고 이것에 대한 더 상세한 설명으로서; 메타 클래스를 사용하여 불변 객체를 만들지 만, 수동으로 상기 설명자를 생성하여 명시 적으로 __slots__을 정의 할 수는 없습니까?

답변

0

속성은 객체의 네이티브 메모리 표현에 할당되고 액세스하는 클래스에 연결된 디스크립터는 실제로 CPython의 네이티브 C 메소드를 사용하여 각 슬롯 속성에 지정된 Python 객체에 대한 참조를 설정 및 검색합니다. 클래스 인스턴스는 C 구조체입니다.

이름 member_descriptor 파이썬에서 제시 슬롯에 대한 설명은, 정의된다 : https://github.com/python/cpython/blob/master/Objects/descrobject.c

당신은 수행하거나 어쨌든에서 순수 파이썬 코드에서 이러한 설명을 향상 할 수 네이티브 코드와 상호 작용하는 ctypes를 사용하지 않고.

class A: 
    __slots__ = "a" 

member_descriptor = type(A.a) 

같은 작업을 수행하여 자신의 유형으로 얻을 수 있습니다 그리고 하나는 chekings 등을 할 수있는 파생 __get____set__ 방법을 그것에서 상속 및 기록 할 수있을 것입니다 supose 수 -하지만 유감스럽게도 기본 클래스로 작동하지 않습니다.

그러나 실제적으로 코드를 변경하기 위해 원시 디스크립터를 호출 할 수있는 다른 병렬 디스크립터를 작성할 수 있습니다. 메타 클래스를 사용하면 클래스 생성시 전달 된 파일의 이름을 __slots__으로 바꿀 수 있으며 추가 검사를 수행 할 수있는 사용자 정의 설명자에 액세스 할 수 있습니다. 심지어 "dir"에서 숨길 수도 있습니다.

그래서, 순진 유형 검사 슬롯 변형 메타 클래스를 위해, 하나는 가질 수

class TypedSlot: 
    def __init__(self, name, type_): 
     self.name = name 
     self.type = type_ 

    def __get__(self, instance, owner): 
     if not instance: 
      return self 
     return getattr(instance, "_" + self.name) 

    def __set__(self, instance, value): 
     if not isinstance(value, self.type): 
      raise TypeError 
     setattr(instance, "_" + self.name, value) 


class M(type): 
    def __new__(metacls, name, bases, namespace): 
     new_slots = [] 
     for key, type_ in namespace.get("__slots__", {}).items(): 
      namespace[key] = TypedSlot(key, type_) 
      new_slots.append("_" + key) 
     namespace["__slots__"] = new_slots 
     return super().__new__(metacls, name, bases, namespace) 

    def __dir__(cls): 
     return [name for name in super().__dir__() if name not in cls.__slots__]