为什么在元组上调用 __reversed__ 会抛出一个属性错误?

问题描述 投票:0回答:3

根据我的理解,我们可以用两种方式调用对象的魔术方法。第一,像这样,像调用普通方法一样调用魔法方法。

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
3个回答
7
投票

大多数魔术方法 不是 等同于其他任何看起来应该等同的东西。__add__ 并不等同于 +. __iadd__ 不等于 +=. __iter__ 不等于 iter. 也不 __getattribute__ 也不 __getattr__ 相当于 getattr 或普通属性访问)。

继续这个模式。__reversed__ 不等于 reversed. 如果 reversed 发现 __reversed__ 方法,它就会使用该方法,但如果不使用,它就只做一个迭代器,用普通的索引从后往前访问参数。这个序列不需要 __reversed__ 方法,以及 tuple 不存在的。


2
投票

你的假设是,必须有一个 __reversed__ 方法是错误的。

reversed(seq)

seq必须是一个有__reversed__()方法的对象。 支持序列协议(__len__()方法和__getitem__()方法,参数从0开始为整数。).


1
投票

因为 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]

文件

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

一般来说,你可能不应该调用dunder方法(因为这是非常危险的方式,特别是在生产代码中),而应该使用特殊的函数类来访问这些方法,如 reversedlen.

© www.soinside.com 2019 - 2024. All rights reserved.