Подтвердить что ты не робот

Почему в Python меняются и сортируются разные типы?

reversed Тип - тип:

>>> type(reversed)
<class 'type'>

sorted Тип - это встроенная функция или метод:

>>> type(sorted)
<class 'builtin_function_or_method'>

Однако они кажутся одинаковыми по своей природе. Исключая очевидную разницу в функциональности (обратная или последовательная сортировка), в чем причина этой разницы в реализации?

4b9b3361

Ответ 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>

Ответ 2

Какая разница между reversed и sorted?

Интересно, что reversed не является функцией, а sorted -.

Откройте сеанс REPL и введите help(reversed):

class reversed(object)
 |  reversed(sequence) -> reverse iterator over values of the sequence
 |  
 |  Return a reverse iterator

Это действительно класс, который используется для возврата обратного итератора.

Хорошо, поэтому reversed не является функцией. Но почему бы и нет?

Это немного сложно ответить. Одно объяснение состоит в том, что итераторы имеют ленивую оценку. Для этого требуется какой-то контейнер для хранения информации о текущем состоянии итератора в любой момент времени. Это лучше всего сделать через объект, а следовательно, class.