简体   繁体   English

将 __slots__ 字典用于初始化目的是有效的 Python 吗?

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

While searching for a convenient method to initialize slots, I had the stupid?在寻找初始化插槽的便捷方法时,我遇到了愚蠢的问题? idea of wrongly?错误的想法 using __slots__ dictionaries as shown below.使用__slots__字典,如下所示。

Note: There is a related question on SO where I've previously posted my idea as answer , but I though it might be more useful to create a new question from it as I'd really like to get more feedback.注意:有一个关于 SO 的相关问题,我之前在其中发布了我的想法作为答案,但我认为从中创建一个新问题可能更有用,因为我真的很想获得更多反馈。

So I'd appreciate any notes/advice/issues for the following "trick":因此,对于以下“技巧”的任何注释/建议/问题,我将不胜感激:

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

Is it ok/safe to do this?这样做可以/安全吗? Are there any drawbacks or possible probelms, etc.?是否有任何缺点或可能的问题等?

Edit:编辑:

After Alex Waygood mentioned the documentation purpose in Python 3.8+, I came up with an extension that also includes a correction for subclassing further - now it's gotten a bit lengthy though: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 say that any iterable containing strings is allowed for __slots__ , but it has a specific warning about mappings: 文档__slots__允许任何包含字符串的迭代,但它有一个关于映射的特定警告:

Any non-string iterable may be assigned to __slots__ .任何非字符串可迭代对象都可以分配给__slots__ Mappings may also be used;也可以使用映射; however, in the future, special meaning may be assigned to the values corresponding to each key.但是,将来可能会为每个键对应的值赋予特殊含义。

I'm not aware of any active proposals to add such special meaning to a mapping used for __slots__ , but that doesn't mean one might not be created in the future.我不知道有任何积极的建议为用于__slots__的映射添加这种特殊含义,但这并不意味着将来可能不会创建。 I would keep an eye out for deprecation warnings as you use this code in future releases!当您在以后的版本中使用此代码时,我会留意弃用警告!

As far as I know , the intended usage of the ability to define __slots__ as a dict is for documentation purposes.据我所知,将__slots__定义为dict的功能的预期用途是用于文档目的。

(I don't know where, if anywhere, this is documented, nor when it was added to Python. I do know that this behaviour is consistent across Python 3.8, 3.9, 3.10, and indeed 3.11 alpha 0 as of 14/10/2021. I haven't tested it on Python <= 3.7.) (我不知道在哪里,如果有的话,这被记录在案,也不知道它何时被添加到 Python 中。我知道这种行为在 Python 3.8、3.9、3.10 和实际上 3.11 alpha 0 中是一致的,截至 14/10/ 2021 年。我还没有在 Python <= 3.7 上测试过。)

If I have a class Foo , like so:如果我有一个类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'
    }

Then calling help(Foo) in the interactive terminal results in the following output:然后在交互式终端中调用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

If I call help() on your Magic class, however, I get the following output:但是,如果我在您的Magic类上调用help()Magic得到以下输出:

>>> 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.

Having said that -- I don't think there's anything anywhere that says that you can't do the kind of thing you propose in your question.话虽如此 - 我认为没有任何地方说你不能做你在问题中提出的那种事情。 It seems to work fine, so if you don't care much about the documentation of your class, and it makes your code more DRY, I say go for it!它似乎工作得很好,所以如果你不太关心你的类的文档,它使你的代码更加 DRY,我说去吧!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM