__slot__
属性是在对象的本机内存表示中分配的,与所访问的类相关联的描述符实际上使用CPython中的本机C方法来设置和检索Python对象的引用,这些Python对象作为C结构归属于类实例上的每个slot属性。
插槽描述符,在Python中以名称显示
member_descriptor
定义如下:
https://github.com/python/cpython/blob/master/Objects/descrobject.c
如果不使用CTypes与本机代码交互,就无法从纯Python代码中执行或增强这些描述符。
可以通过以下操作来达到他们的类型
class A:
__slots__ = "a"
member_descriptor = type(A.a)
然后我们就可以从中继承并编写派生的
__get__
和
__set__
可以进行检查之类的方法,但不幸的是,它不能作为基类工作。
但是,可以编写其他并行描述符,这些描述符可以调用本机描述符来实际存储值。
通过使用元类,可以在类创建时重命名传入的
__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__]