Ответ 1
Разница в том, что reversed
является итератором (он также лениво оценивается), а sorted
- это функция, которая работает "с нетерпением".
Все встроенные итераторы (по крайней мере, в python-3.x), такие как map
, zip
, filter
, reversed
,... реализованы как классы. В то время как встроенные встроенные функции с нетерпением - функции, например. min
, max
, any
, all
и sorted
.
>>> a = [1,2,3,4]
>>> r = reversed(a)
<list_reverseiterator at 0x2187afa0240>
Вам действительно нужно "потреблять" итератор для получения значений (например, list
):
>>> list(r)
[4, 3, 2, 1]
С другой стороны, эта "потребляющая" часть не нужна для функций, таких как sorted
:
>>> s = sorted(a)
[1, 2, 3, 4]
В комментариях было задано , почему они реализованы как классы вместо функций. На это не очень легко ответить, но я постараюсь изо всех сил:
Использование лениво-оценочных операций имеет одно огромное преимущество: они очень эффективны с памятью при приковании. Им не нужно создавать промежуточные списки, если они явно не запрошены. Именно поэтому map
, zip
и filter
были изменены с нетерминальных рабочих функций (python-2.x) на ленивые рабочие классы (python-3.x).
Как правило, в Python существует два способа создания итераторов:
- которые
return self
в своем методе__iter__
- функции генератора - функции, содержащие
yield
Однако (по крайней мере, CPython) реализует все свои встроенные модули (и несколько стандартных модулей библиотеки) на C. Очень легко создавать классы итераторов в C, но я не нашел разумного способа создания функций генератора на основе Python-C API. Поэтому причина, по которой эти итераторы реализованы как классы (в CPython), может быть просто удобством или отсутствием (быстрыми или реализуемыми) альтернативами.
Существует дополнительная причина использовать классы вместо генераторов: вы можете применять специальные методы для классов, но вы не можете реализовать их на функциях генератора. Это может показаться не впечатляющим, но оно имеет определенные преимущества. Например, большинство итераторов может мариноваться (по крайней мере, на Python-3.x) с помощью __reduce__
и __setstate__
. Это означает, что вы можете сохранить их на диске и разрешить их копирование. Начиная с Python-3.4, некоторые итераторы также реализуют __length_hint__
, что значительно ускоряет использование этих итераторов с list
(и аналогичным).
Обратите внимание, что reversed
может быть легко реализована как factory -функция (например, iter
), но в отличие от iter
, которая может возвращать два уникальных класса, reversed
может только возвращаться один уникальный класс.
Чтобы проиллюстрировать возможные (и уникальные) классы, вы должны рассмотреть класс, который не имеет __iter__
и no __reversed__
, но являются итерабельными и обратными итерабельными (путем реализации __getitem__
и __len__
):
class A(object):
def __init__(self, vals):
self.vals = vals
def __len__(self):
return len(self.vals)
def __getitem__(self, idx):
return self.vals[idx]
И хотя имеет смысл добавить слой абстракции (factory) в случае iter
- потому что возвращаемый класс зависит от количества входных аргументов:
>>> iter(A([1,2,3]))
<iterator at 0x2187afaed68>
>>> iter(min, 0) # actually this is a useless example, just here to see what it returns
<callable_iterator at 0x1333879bdd8>
Это рассуждение не относится к reversed
:
>>> reversed(A([1,2,3]))
<reversed at 0x2187afaec50>