【问题标题】:Why does calling __reversed__ upon a tuple throw an attribute error?为什么在元组上调用 __reversed__ 会引发属性错误?
【发布时间】:2020-08-16 09:57:00
【问题描述】:

据我了解,可以通过两种方式之一调用对象的魔法方法。首先像这样,魔术方法像任何常规方法一样被调用:

x = (1, 2, 3, 4)
print(x.__len__())
#prints 4

其次,像这样,魔术方法被称为“特殊”:

x = (1, 2, 3, 4)
print((len(x)))
#prints 4

正如我们所见,两者是等价的。但是,当我使用第一种方式在一个元组上调用魔术方法 reversed() 时,我遇到了一个错误:

x = (1, 2, 3, 4)
x.__reversed__()
#causes an attribute error

然而,调用反转方法的“特殊”方式工作得非常好:

x = (1, 2, 3, 4)
reversed(x)
#returns a reversed object

为什么会发生这种情况?我对 dunder 方法有误解吗?

【问题讨论】:

标签: python python-3.x tuples


【解决方案1】:

大多数魔法方法并不等同于它们看起来应该等同的任何其他事物。 __add__ 不等于 +__iadd__ 不等于 +=__iter__ 不等于 iter__getattribute____getattr__ 都不等同于 getattr(或普通属性访问)。

继续这个模式,__reversed__ 不等于 reversed。如果reversed 找到__reversed__ 方法,它将使用该方法,但如果没有,它只会创建一个迭代器,使用普通索引从后到前访问参数。该序列不需要__reversed__ 方法,而tuple 没有。

【讨论】:

  • 啊,有道理。但是如果我在一个没有 iter 方法的对象上调用 iter 呢?那么事情不会变得时髦吗?
  • @Dude156: __iter____reversed__ 具有相同的后备功能,但索引是从前到后而不是从后到前。
  • 但我的意思是,如果我们在没有 __iter__ 的对象时调用 iter(),该方法怎么知道如何创建迭代器...?
【解决方案2】:

您认为必须有__reversed__ 方法的假设是错误的:

reversed(seq)

返回一个反向迭代器。 seq 必须是具有 __reversed__() 方法的对象支持序列协议(__len__() 方法和 __getitem__() 方法,整数参数从 0 开始) .

【讨论】:

    【解决方案3】:

    因为reversed 会根据参数执行以下操作之一:

    1. Argument 是一个具有__reversed__ 魔术方法的对象,reversed 只是调用它并返回给定的迭代器。
    >>> class A:
    ...     def __reversed__(self):
    ...         yield 17
    ...         yield 42
    >>> a = A()
    >>> reversed(a)
    <generator object A.__reversed__ at 0x7fa1283e8e40>
    >>> list(reversed(a))
    [17, 42]
    
    1. 参数是一个序列(如tuplestr),它具有__len____getitem____reversed__ 创建一个中间对象,该对象产生从最后一个到第一个的序列元素。
    >>> t = (42, 17)
    >>> reversed(t)
    <reversed object at 0x7fa12840fc40>
    >>> list(reversed(t))
    [17, 42]
    

    来自docs

    reversed(seq) 返回一个反向迭代器。 seq 必须是具有 __reversed__() 方法或支持序列协议的对象(__len__() 方法和 __getitem__() 方法,整数参数从 `0 开始)。

    更一般地,您可能不应该调用 dunder 方法(因为这是非常危险的方法,尤其是在生产代码中)并使用特殊的函数/类来访问它们,例如 reversed/len

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-09-05
      • 2013-10-25
      • 1970-01-01
      • 2015-09-02
      • 1970-01-01
      • 2016-03-12
      • 1970-01-01
      相关资源
      最近更新 更多