不可变类和__copy__

时间:2017-02-09 13:10:58

标签: python

对于旨在用作不可变的类,例如:

class Immutable:
    def __init__(self, field):
        self._field = field
    def field(self):
        return self._field

没关系,可以在self中返回__copy__吗?

    def __copy__(self):
        return self

1 个答案:

答案 0 :(得分:1)

如果您的目标是让您的班级用户可以安全地在其实例上调用copy.copy,那么请务必随时添加__copy__方法:

def __copy__(self): 
    return self

然而,这并非真的有必要。你的类的文档应该清楚它的实例是不可变的,所以任何使用你的类的人都应该知道,如果他们想在多个地方引用它,他们可以安全地重新使用一个实例,就像它们使用内置实例一样。在intstrtuplefrozenset等不可变类型中。例如,

a, b, c = Immutable(123), Immutable(456), 42
d = {'one': a, 'two': b, 'three': c}

如果你没有提供__copy__方法而某人 在某个实例上调用copy.copy,那么他们将获得一个新对象,该对象是原始对象的克隆实例。如上所述定义__copy__,他们当然只会获得对原始对象的引用。

顺便说一句,你应该将.field(以及任何其他属性)变成property,并且不提供制定者。

class Immutable:
    def __init__(self, field):
        self._field = field

    @property
    def field(self):
        return self._field

现在您可以将字段方法称为简单属性:

a = Immutable(123) 
print(a.field)

当然,您仍然可以以正常方式改变._field属性,但是任何使用您的类的人都应该知道他们不应该这样做。 :)

在问题评论中,我们讨论了在元组上调用copy.copy会返回对原始元组的引用这一事实,即使tuple未定义__copy__。没有内置类型定义__copy__,但要记住它们都是用C定义的,因此它们与Python中定义的类的工作方式略有不同。 FWIW,在任何内置的不可变类型上调用copy.copy都会返回对原始对象的引用,并且在任何内置的可变类型上调用copy.copy都会返回一个克隆。