【问题标题】:Is it valid Python to use a __slots__ dictionary for initialization purposes?使用 __slots__ 字典进行初始化是否有效?
【发布时间】:2021-11-28 05:35:39
【问题描述】:

在寻找初始化槽的便捷方法时,我产生了愚蠢?的想法错误地?使用__slots__字典,如下所示。

注意:在 SO 上有一个相关的 question,我之前将我的想法发布为answer,但我认为从中创建一个新问题可能更有用,因为我真的很想得到更多反馈。

因此,对于以下“技巧”的任何注释/建议/问题,我将不胜感激:

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

这样做可以/安全吗? 有没有什么缺点或可能的问题等?

编辑:

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

【问题讨论】:

  • 我喜欢这个! (尽管我敢打赌它会对类型检查器造成严重破坏——但是,嘿,你不能拥有一切!)

标签: python python-3.x slots


【解决方案1】:

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

任何非字符串可迭代对象都可以分配给__slots__。也可以使用映射;但是,将来可能会为每个键对应的值赋予特殊的含义。

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

【讨论】:

    【解决方案2】:

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

    (我不知道这是在哪里记录的,也不知道何时添加到 Python。我知道这种行为在 Python 3.8、3.9、3.10 和 3.11 alpha 0 中是一致的截至 2021 年 10 月 14 日。我尚未在 Python

    如果我有一个班级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 类上调用 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.
    

    话虽如此 - 我认为没有任何地方可以说您不能做您在问题中提出的那种事情。它似乎工作得很好,所以如果你不太关心你的类的文档,并且它使你的代码更干燥,我说去吧!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-13
      • 1970-01-01
      • 1970-01-01
      • 2021-12-08
      • 1970-01-01
      • 2022-11-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多