什么是使一个不可变类的Pythonic方法?

2024-04-25 16:50:43 发布

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

我目前正在用Python处理一些数据结构,我希望它们是可散列的(这样它们就可以存储在字典和集合中)。到目前为止,我已经看到了三种主要的方法:

①构造一个普通类并给它一个__hash__方法。你知道吗

class DataStructure:
    def __init__(self, member):
        self.member = member
    def __hash__(self):
        return hash(self.member)
    def __eq__(self, other):
        return isinstance(other, DataStructure) and self.member == other.member

但这只是“相信”最终用户永远不会变异member。如果他们在把它存储在集合或字典中的时候对它进行了变异,就会产生不好的结果。你知道吗

②使用collections.namedtuple。你知道吗

DataStructure = collections.namedtuple('DataStructure', ('member',))

但是namedtuple不能有成员函数,如果有成员函数就更好了。你知道吗

③使用__slots__并重写__setattr__,如here所示。你知道吗

class DataStructure:
    __slots__ = ['member']
    def __init__(self, member):
        super(DataStructure, self).__setattr__('member', member)
    def __setattr__(self, key, value):
        raise ValueError('Mutating this object is Not Allowed')
    # also define __hash__ and __eq__ here

但是这个doesn't seem to be intended usage,也使得继承更加复杂。最重要的是,它不觉得“Python”。你知道吗

那么:在Python中创建不可变类的首选方法是什么?希望自定义数据结构是可散列的似乎并不奇怪,毕竟这就是__hash__存在的原因。我更愿意让类变为不可变的,而不是告诉用户“您可以自由地分配给这些成员,但是如果这样做,您的集合和字典可能会崩溃和烧毁”——Python通常会首先尝试不让人们犯这些错误(这就是setfrozenset是不同的原因)。你知道吗


Tags: 方法self数据结构return字典initdef成员
2条回答

在要“只读”的变量前面加一个“\”。它仍然可以从类内更改,但是IDE不会预测它,如果您尝试从类外更改它们,它会抛出警告。你知道吗

__slots__ = ('_member',)

绝对的不可变性可能无法实现,但您可以使用properties来明确您的意图:

class DataStructure:
    def __init__(self, member):
        self._member = member
    def __hash__(self):
        return hash(self.member)
    def __eq__(self, other):
        return isinstance(other, DataStructure) and self.member == other.member
    @property
    def member(self):
        return self._member

这样member作为“public”属性公开,但不可写:

>>> ds = DataStructure(42)
>>> ds.member
42
>>> ds.member = 56
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

一个坚定的最终用户仍然可以变异self._member,但是在这一点上,你会期望他们知道他们做了错误的事情。你知道吗

相关问题 更多 >