2017-12-27 143 views
0

我知道__slots__做什么,它应该用于什么。__slot__描述符如何在python中工作?

但是,我还没有找到一个全面的答案,如何使用__slots__创建的member描述符的下层机制的作品。

对象级别的值在哪里实际存储?

有没有办法改变这些值,而不直接属性访问描述符?
(例如:上课时C__dict__你可以做C.__dict__['key']代替C.key

通过创建类似的类级别的描述可以在一个“扩展” __slots__对象定义的不变性?并进一步阐述这一点;可以使用元类构建一个不可变的对象,但是通过手动创建所述描述符来明确定义__slots__

回答

0

__slot__属性被分配在该对象的本机存储器的表示,和相关联的访问然后实际的类描述符使用本地C方法CPython的设置和检索归因于每个时隙中的Python对象的参考属性上类实例作为C结构。

描述符的插槽,在Python名为member_descriptor呈现在这里定义:https://github.com/python/cpython/blob/master/Objects/descrobject.c

您不能执行或以任何方式提高从纯Python代码,这些描述符不使用ctypes的与本地代码进行交互。

有可能通过做类似

class A: 
    __slots__ = "a" 

member_descriptor = type(A.a) 

去他们的类型,那么可以supose将有可能继承它,并写出推导__get____set__方法,可以做到chekings和这样的 - 但不幸的是,它不能作为基类。

但是,可以编写其他并行描述符,这些描述符可以调用本地描述符来实际更改代码。 通过使用元类,可以在创建类时重命名传入的__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__]