[英]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.