Python中使用__slots__字典实现属性初始化是否合法安全?
我在寻找便捷的slots初始化方法时,冒出了不知道算不算愚蠢、算不算错误的想法:如下所示将__slots__字典用于初始化用途。
注意:我此前曾将我的思路作为答案发布在相关问题下,但我认为单独提出新问题能获得更多反馈,因此创建了本问询。
希望大家能就以下这个“小技巧”给出说明、建议或是指出可能存在的问题:
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
这么做是否合规、安全?存在什么缺陷或是潜在问题?
编辑:
在有开发者提到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
内容的提问来源于stack exchange,提问作者P. B.
相关产品推荐
相关产品推荐

