Python __slots__ 元类问题

Python __slots__ metaclass issue

我目前正在使用 type():

实现开槽元类
type(i, (), {'__slots__': tuple(data)

我当然会理想地保留插槽,因为我有一个用例,可以受益于它们更小的内存占用和更高的访问速度。

当我这样做时:

dir(slotted_class)
>>>['__class__',
 '__delattr__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__gt__',
 '__hash__',
 '__init__',
 '__init_subclass__',
 '__le__',
 '__lt__',
 '__module__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__slots__',
 '__str__',
 '__subclasshook__',
 'slotted_attribute1',
 'slotted_attribute2',
 'slotted_attribute3',
 'slotted_attribute4']

然而当我运行:

slottedclass.slotted_attribute1

我收到以下错误:

    >>> AttributeError                            Traceback (most recent call last)
<ipython-input-58-88291109fa74> in <module>()
----> 1 slotted_class.slotted_attribute1

AttributeError: slotted_attribute1

编辑:更多信息和更多困惑: 如果我不使用元类直接实现一个等价物:

class slottedclass_non_meta(object):
__slots__ = ['slotted_attribute1', 'slotted_attribute2', 'slotted_attribute3', 'slotted_attribute4']

def __init__(self, slotted_attribute1, slotted_attribute2, slotted_attribute3, slotted_attribute4):
    self.slotted_attribute1, self.slotted_attribute2, self.slotted_attribute3, self.slotted_attribute4 = slotted_attribute1, slotted_attribute2, slotted_attribute3, slotted_attribute4

然后做这个对比 目录(开槽类)== 目录(slottedclass_non_meta)

>>> True

这可能只是您的 data 变量的一些错误。制作 确保它是可迭代的或字符串序列。

在我的交互式环境中尝试这个完美无缺:

In [162]: m = type("m", (), {"__slots__": ("test1",)})

In [163]: m.test1
Out[163]: <member 'test1' of 'm' objects>

In [164]: n = m()

In [165]: n.test1 = 10

In [166]: n.test1
Out[166]: 10

其他注意事项:

  • 为此您不需要说您是 "using metaclasses"(尽管从技术上讲您是)- 只需说您正在通过调用 type 动态创建 classes。在阅读问题标题时,大多数人会认为您正在尝试专门化 type 本身并在其中包含 __slots__
  • 在您粘贴的示例代码中,您没有用于动态创建的 class 的 __init__ 方法:因此您显然无法在 [=34= 上传递名称参数] 创建并在实例上自动设置它们,就像您在显式 class.
  • 上所做的那样

如果第二个主题是你的问题,我建议不要继承 object(暗示但他是空的 - () - 要调用的第二个参数),创建一个具有泛型的 baseclass __init__ 将 kwargs 设置为属性的方法:

class Base:
   __slots__ = ()
   def __init__(self, **kwargs):
       for key, value in kwargs.items():
           setattr(self, key, value)

slotted_class  = type("slotted_class", (Base,), {"__slots__": ...})