Why do tuples in Python work with reversed but do

2019-06-28 02:56发布

问题:

In discussion of this answer we realized that tuples do not have a __reversed__ method. My guess was that creating the iterator would require mutating the tuple. And yet tuples play fine with reversed. Why can't the approach used for reversed be made to work for __reversed__ as well?

>>> foo = range(3)
>>> foo
[0, 1, 2]
>>> list(foo.__reversed__())
[2, 1, 0]
>>> foo
[0, 1, 2]
>>> bar = (0, 1, 2)
>>> list(bar.__reversed__())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute '__reversed__'
>>> reversed(bar)
<reversed object at 0x10603b310>
>>> tuple(reversed(bar))
(2, 1, 0)

回答1:

According to the spec:

reversed(seq)

Return a reverse iterator. seq must be an object which has a reversed() method or supports the sequence protocol (the __len__() method and the __getitem__() method with integer arguments starting at 0).



回答2:

EDIT: well, I try to say it again (english is not my native language) - with example.

Some functions - I call them fun(object) - can use object.__func__() to do the job or they use other functions in object if there is no object.__func__()

-

For example str() - when you use str(object) it calls object.__str__(), but if there is no object.__str__() then it calls object.__repr__().

So you can use str() with object which has no __str__() and still get some result.

-

Other example < - when you use a < b it tries to use a.__lt__() but if there is no a.__lt__() it tries to use a.__gt__() (and maybe other functions too)

class MyClass():

    def __str__(self):
        return "MyClass: __str__"

    def __repr__(self):
        return "MyClass: __repl__"

    #-------------------------

    def __lt__(self, other):
        return True

    def __gt__(self, other):
        return True

    #-------------------------

a = MyClass()
b = MyClass()

print( str(a) )

print( a < b )
  1. You can remove __str__ to get different result.

  2. You can change True/False in __lt__ and you can see that result is changed.
    Then you can remove __lt__ and you can change True/False in __gt__ and you see that result is changed again.