Python: 不应该使用的魔术方法

Python: magic methods that shouldn't be used

我创建了一个 class,它是一个 tuple 包装器,元组不支持项目突变。 我应该离开 __setitem____delitem__ 实现还是实现那些方法,例如下面(因此有点像 Refused Bequest 代码的味道)?哪种方法更pythonic?在这种情况下自定义异常不是更好吗?

def __setitem__(self, key, value):
    """
    :raise: Always.
    :raises: TypeError
    """
    self.data_set[key] = value  # Raise from tuple.

def __delitem__(self, key):
    """
    :raise: Always.
    :raises: TypeError
    """
    raise TypeError("Item deletion is unsupported")  # Custom exceptions thrown.

如果它们对您的自定义有意义,则实施其中之一或同时实施两者 class。

如果您实施 __setitem__(),您将能够在代码中使用 yourobject[yourindex] = yourvalue 语法(使用您选择实施的语义)。

如果您实施 __delitem__(),您将能够使用 del yourobject[yourindex]

显式实现一个方法只是为了引发异常是没有意义的,Python 默认情况下会这样做:

class Test(object):
    pass
test = Test()
test['foo'] = 'bar' # will call Test.__setitem__() which is not explicitly defined

会给TypeError: 'Test' object does not support item assignment

尽管这是个人喜好问题,但我认为您根本不应该实施它们。具有 __setitem__, __delitem__ 的 class 实现可变集合 协议 (隐式地,甚至通过使用 collection abstract base classes 显式地实现)。你的class只是不支持这个接口,就是这样,用户没有理由也没有权利假设它支持

如果你的 class 应该是一个正确的元组子类型(根据 Liskov substitution principle),那么它的行为应该与元组 wrt/ 到 set/del 的行为相同 - 这正如 Guillaume 提到的那样,如果您既不定义 __setitem__ 也不定义 __delitem__,这是默认行为。我不明白那怎么会属于 "Refused Bequest" 类别。

如果您的 class 在其实现中使用了一个元组但不应该是一个正确的元组子类型,那么做任何有意义的事情 - 但如果您不想允许项目分配/删除那么最简单的事情就是不实施它们。