在Python中创建不可变对象

2024-09-24 00:36:12 发布

您现在位置:Python中文网/ 问答频道 /正文

我想在python中创建一个像dictionary这样的不可变类。我在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

Tags: inselfobjectinitdefargsupdateproperties
1条回答
网友
1楼 · 发布于 2024-09-24 00:36:12

您可以将类中所需的唯一属性添加到插槽中,如下所示

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')

    __slots__ =('k')


x = Immutable(k=5)
print(x.k) # 5 as expected
x.__dict__.update({'k': 7}) # should raise error or update copy of x
print(x.a) # 7, thus object is still mutable

输出

5
Traceback (most recent call last):
  File "inmutable.py", line 24, in <module>
    x.__dict__.update({'k': 7}) # should raise error or update copy of x
AttributeError: 'Immutable' object has no attribute '__dict__'

相关问题 更多 >