【问题标题】:Python: magic methods that shouldn't be usedPython:不应该使用的魔法方法
【发布时间】:2016-11-22 12:48:22
【问题描述】:

我创建了一个 tuple 包装类,并且元组不支持项目突变。 我应该离开__setitem____delitem__ 实现还是实现这些方法,例如下面(因此属于拒绝遗赠代码的味道)?哪种方法更 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.

【问题讨论】:

    标签: python coding-style magic-methods


    【解决方案1】:

    如果你的类应该是一个正确的元组子类型(根据Liskov substitution principle),那么它的行为方式应该与元组 wrt/ 到 set/del 的方式相同 - 正如 Guillaume 所提到的,如果你只是既不定义 __setitem__ 也不定义 __delitem__。我看不出这怎么会属于“拒绝遗赠”类别。

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

    【讨论】:

    • 拒绝遗赠我的意思是这个类声称实现__setitem____delitem__,但它的行为表明它不支持这些操作。
    • 正常。实际上(正如我提到的)如果目标是不支持项目分配和删除,那么实现这些方法确实没有意义。
    【解决方案2】:

    虽然这是一个口味问题,但我认为您根本不应该实施它们。具有__setitem__, __delitem__ 的类实现了可变集合protocol(隐式地,甚至使用collection abstract base classes 显式地实现)。你的类只是不支持这个接口,就是这样,用户没有理由也没有权利假设它支持

    【讨论】:

      【解决方案3】:

      如果它们对您的自定义类有意义,则实现其中一个或另一个或两者。

      如果您实现__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

      【讨论】:

        猜你喜欢
        • 2020-07-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-29
        • 1970-01-01
        相关资源
        最近更新 更多