【发布时间】:2020-01-14 14:30:48
【问题描述】:
我想在 python 中创建一个像字典一样的不可变类。我在 stackoverflow 上找到了以下解决方案,但是这个对象的值可以通过使用 __dict__.update 函数来更新。有没有办法阻止这个动作。
class Immutable(object):
def __init__(self, **kwargs):
"""Sets all values once given
whatever is passed in kwargs
"""
for k, v in kwargs.items():
object.__setattr__(self, k, v)
def __setattr__(self, *args):
"""Disables setting attributes via
item.prop = val or item['prop'] = val
"""
raise TypeError('Immutable objects cannot have properties set after init')
def __delattr__(self, *args):
"""Disables deleting properties"""
raise TypeError('Immutable objects cannot have properties deleted')
x = Immutable(a=5)
print(x.a) # 5 as expected
x.__dict__.update({'a': 7}) # should raise error or update copy of x
print(x.a) # 7, thus object is still mutable
解决方案
正如DeepSpace 在评论中提到的那样,通过实现__getattr__ 来阻止对__dict__ 的访问。
我已经实施了以下解决方案并且它有效
class Immutable(object):
def __init__(self, **kwargs):
"""Sets all values once given
whatever is passed in kwargs
"""
for k, v in kwargs.items():
object.__setattr__(self, k, v)
def __getattribute__(self, item):
result = super(Immutable, self).__getattribute__(item)
if item == '__dict__':
return dict(**result)
return result
def __setattr__(self, *args):
"""Disables setting attributes via
item.prop = val or item['prop'] = val
"""
raise TypeError('Immutable objects cannot have properties set after init')
def __delattr__(self, *args):
"""Disables deleting properties"""
raise TypeError('Immutable objects cannot have properties deleted')
x = Immutable(a=5)
print(x.a) # 5
x.__dict__.update({'a': 7}) # update value on a copy of dict which has no effect
print(x.a) # 5 this time object value remain same
【问题讨论】:
-
FWIW,
dict不是一成不变的。 -
这能回答你的问题吗? How to make an immutable object in Python?
-
无论如何,你可以通过实现
__getattr__来阻止对__dict__的访问 -
__init__在对象创建后 被调用,这意味着只有self是可变的,才能添加属性。使用__new__强调您的对象是(准)不可变的。
标签: python python-3.x immutability