Python 使用 __slots__ 字典进行初始化是否有效?

Is it valid Python to use a __slots__ dictionary for initialization purposes?

在寻找初始化插槽的便捷方法时,我有一个 愚蠢的想法? wrongly? using __slots__字典如下所示。

注意:有一个相关的 on SO where I've previously posted my idea as ,但我认为从中创建一个新问题可能更有用,因为我真的很想获得更多反馈。

因此,对于以下“技巧”,我将不胜感激 notes/advice/issues:

class Slotted:

    __slots__ = {}

    def __new__(cls, *args, **kwargs):
        inst = super().__new__(cls)
        for key, value in inst.__slots__.items():
            setattr(inst, key, value)
        return inst

class Magic(Slotted):

    __slots__ = {
        "foo": True,
        "bar": 17
    }
magic = Magic()

print(f"magic.foo = {magic.foo}")
print(f"magic.bar = {magic.bar}")
magic.foo = True
magic.bar = 17

是ok/safe要这样做吗? 有没有什么缺点或者可能的问题等等?

编辑:

Alex Waygood 提到 Python 3.8+ 中的文档目的之后,我提出了一个扩展,其中还包括对进一步子类化的更正 - 虽然现在它有点冗长:

class Slot(str):

    __slots__ = ["init"]

    def __new__(cls, init, doc=""):
        obj = str.__new__(cls, doc)
        obj.init = init
        return obj

    def __call__(self):
        return self.init

class Slotted:

    __slots__ = {}

    def __new__(cls, *args, **kwargs):
        obj = super().__new__(cls)
        for base in reversed(cls.__mro__[:-1]):
            if isinstance(base.__slots__, dict):
                for key, value in base.__slots__.items():
                    if isinstance(value, Slot):
                        setattr(obj, key, value())
                    else:
                        raise TypeError(
                            f'Value for slot "{key}" must'
                            f' be of type "{Slot.__name__}"'
                        )
        return obj
class Magic(Slotted):
    """This class is not so boring any more"""

    __slots__ = {
        "foo": Slot(2, doc="Some quite interesting integer"),
        "bar": Slot(3.1416, doc="Some very exciting float")
    }

help(Magic)
magic = Magic()
print(f"magic.__slots__ = {magic.__slots__}")
print(f"magic.foo = {magic.foo}")
print(f"magic.bar = {magic.bar}")
Help on class Magic in module __main__:

class Magic(Slotted)
 |  Magic(*args, **kwargs)
 |  
 |  This class is not so boring any more
 |  
 |  Method resolution order:
 |      Magic
 |      Slotted
 |      builtins.object
 |  
 |  Data descriptors defined here:
 |  
 |  bar
 |      Some very exciting float
 |  
 |  foo
 |      Some quite interesting integer
 |  
 |  ----------------------------------------------------------------------
 |  Static methods inherited from Slotted:
 |  
 |  __new__(cls, *args, **kwargs)
 |      Create and return a new object.  See help(type) for accurate signature.

magic.__slots__ = {'foo': 'Some quite interesting integer', 'bar': 'Some very exciting float'}
magic.foo = 2
magic.bar = 3.1416

The docs__slots__ 允许任何包含字符串的迭代器,但它有一个关于映射的特定警告:

Any non-string iterable may be assigned to __slots__. Mappings may also be used; however, in the future, special meaning may be assigned to the values corresponding to each key.

我不知道有任何活跃的提议将这种特殊含义添加到用于 __slots__ 的映射中,但这并不意味着将来可能不会创建。当您在未来的版本中使用此代码时,我会留意弃用警告!

据我所知,将__slots__定义为dict的功能的预期用途是用于文档目的。

(我不知道这是在何处记录的,也不知道它是何时添加到 Python 中的。我知道这种行为在 [=37= 中是一致的] 3.8、3.9、3.10,实际上是 3.11 alpha 0,截至 2021 年 10 月 14 日。我还没有在 Python <= 3.7 上测试过它。)

如果我有 class Foo,像这样:

class Foo:
    """The Foo class is for doing Foo-y things (obviously)."""
    
    __slots__ = {
        'bar': 'Some information about the bar attribute',
        'baz': 'Some information about the baz attribute'
    }

然后在交互式终端中调用 help(Foo) 会产生以下输出:

>>> help(Foo)
Help on class Foo in module __main__:

class Foo(builtins.object)
 |  The Foo class is for doing Foo-y things (obviously).
 |  
 |  Data descriptors defined here:
 |  
 |  bar
 |      Some information about the bar attribute
 |  
 |  baz
 |      Some information about the baz attribute

如果我在您的 Magic class 上调用 help(),但是,我得到以下输出:

>>> help(Magic)
Help on class Magic in module __main__:

class Magic(Slotted)
 |  Magic(*args, **kwargs)
 |  
 |  Method resolution order:
 |      Magic
 |      Slotted
 |      builtins.object
 |  
 |  Data descriptors defined here:
 |  
 |  bar
 |  
 |  foo
 |  
 |  ----------------------------------------------------------------------
 |  Static methods inherited from Slotted:
 |  
 |  __new__(cls, *args, **kwargs)
 |      Create and return a new object.  See help(type) for accurate signature.

话虽如此——我认为没有任何地方表明您不能做您在问题中提出的那种事情。它似乎工作正常,所以如果你不太关心你的 class 的文档,它会让你的代码更枯燥,我建议你去吧!