修改不可变类实例

时间:2012-06-01 14:04:01

标签: python python-2.7 immutability

我有一个有点复杂的数据类型Mask,我希望能够使用快速身份检查,例如:

seen = set()
m = Mask(...)
if m in seen:
    ...

这表明Mask应该 hashable ,因此不可变。但是,我想生成mMask的变体似乎是封装变体逻辑的地方。这是一个简洁的例子,展示了我想要实现的目标:

class Mask(object):
    def __init__(self, seq):
        self.seq = seq
        self.hash = reduce(lambda x, y: x ^ y, self.seq)

    # __hash__ and __cmp__ satisfy the hashable contract §3.4.1)
    def __hash__(self):
        return self.hash

    def __cmp__(self, other):
        return cmp(self.seq, other.seq)

    def complement(self):
        # cannot modify self without violating immutability requirement
        # so return a new instance instead
        return Mask([-x for x in self.seq])

这满足所有可清除和不可变的属性。特点是有效的工厂方法complement;这是实现所需功能的合理方式吗?请注意,我根本没有兴趣防范“恶意”修改,因为许多相关问题正在寻求实现。

由于这个例子很小,所以可以通过制作seq的元组来轻松解决。我实际使用的类型不能提供如此简单的铸造。

3 个答案:

答案 0 :(得分:2)

是的,这几乎就是你编写一个不可变类的方法;在你的术语中,否则会改变对象状态的方法将成为创建新实例的“工厂”。

请注意,在计算补码的特定情况下,您可以将方法命名为__invert__并将其用作

inv_mask = ~mask

运算符语法是客户端代码的强信号,操作返回相同类型的新值。

答案 1 :(得分:1)

当使用不可变类型时,所有“变体”方法都必须返回新的对象/实例,因此就是这种意义上的工厂。

许多语言使字符串不可变(包括Python)。所以所有字符串操作都返回新字符串strB = strA.replace(...)等。

如果你可以改变实例,它就不会是不可变的。

编辑:

重读,你问这是否合理,我说是的。逻辑不会更好地放在其他地方,正如我用字符串不变性指出的那样,从现有的变量中获取新的变化是一种常见的范例。

答案 2 :(得分:1)

Python不会强制实现不变性。您可以确保对象在set中时不会被修改。否则,您不需要在Python中使用集合,字典的不可变性。