Обратные списки Python: Beyond .reverse() и reversed()

Оглавление

Вы углубляетесь в изучение списков Python и хотите узнать о различных способах их изменения? Если да, то это руководство для вас. Здесь вы узнаете о нескольких инструментах и приемах Python, которые пригодятся, когда дело доходит до изменения списков или манипулирования ими в обратном порядке. Эти знания дополнят и улучшат ваши навыки работы со списками и помогут вам лучше с ними справляться.

В этом руководстве вы узнаете, как:

  • Отменить существующие списки на месте, используя .reverse() и другие методы
  • Создайте перевернутые копии существующих списков, используя reversed() и нарезку
  • Используйте итерацию, повторения и рекурсию для создания обратных списков
  • Выполните итерацию по вашим спискам в обратном порядке
  • Отсортируйте ваших списков в обратном порядке, используя .sort() и sorted()

Чтобы извлечь максимальную пользу из этого руководства, было бы полезно ознакомиться с основами итераций, for циклов, списков, понимания списков, генераторные выражения и рекурсия.

Бесплатный бонус: Нажмите здесь, чтобы получить шпаргалку по Python и изучить основы Python 3, такие как работа с типами данных, словари, списки и функции Python.

Реверсирование списков Python

Иногда вам нужно обрабатывать списки Python, начиная с последнего элемента и заканчивая первым — другими словами, в обратном порядке. В целом, существует две основные проблемы, связанные с работой со списками в обратном порядке:

  1. Изменение существующего списка местами
  2. Создание измененных копий существующего списка

Для решения первой задачи вы можете использовать либо .reverse(), либо цикл, который меняет местами элементы по индексу. Для второго вы можете использовать reversed() или операцию нарезки. В следующих разделах вы узнаете о различных способах выполнения того и другого в вашем коде.

Измененные списки на месте

Как и другие типы изменяемых последовательностей, списки Python реализуют .reverse(). Этот метод переворачивает базовый список на место для экономии памяти при переворачивании объектов большого списка. Вот как вы можете использовать .reverse():

>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> digits.reverse()
>>> digits
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]


Когда вы вызываете .reverse() для существующего списка, метод изменяет его на противоположный. Таким образом, при повторном обращении к списку вы получите его в обратном порядке. Обратите внимание, что .reverse() не возвращает новый список, но None:

>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> reversed_digits = digits.reverse()
>>> reversed_digits is None
True


Попытка присвоить возвращаемое значение .reverse() переменной является распространенной ошибкой, связанной с использованием этого метода. Цель возврата None состоит в том, чтобы напомнить своим пользователям, что .reverse() работает с помощью побочного эффекта, изменяя базовый список.

Примечание: В большинстве примеров в этом руководстве в качестве входных данных используется список из чисел. Однако те же инструменты и методы применимы к спискам объектов Python любого типа, таким как списки строк.

Хорошо! Это было быстро и просто! Итак, как вы можете изменить список вручную? Общепринятый метод заключается в циклическом просмотре первой половины списка, заменяя каждый элемент его зеркальным аналогом во второй половине списка.

Python предоставляет основанные на нуле положительные индексы для перемещения последовательностей слева направо. Он также позволяет перемещаться по последовательностям справа налево, используя отрицательные индексы:

Python list with indices

На этой диаграмме показано, что вы можете получить доступ к первому элементу списка (или последовательности), используя либо 0, либо -5 с помощью оператора индексирования, как в sequence[0] и sequence[-5], соответственно. Вы можете использовать эту функцию Python, чтобы изменить базовую последовательность на месте.

Например, чтобы перевернуть список, представленный на диаграмме, вы можете выполнить цикл по первой половине списка и поменять местами элемент с индексом 0 с его зеркальным отображением с индексом -1 на первой итерации. Затем вы можете поменять элемент с индексом 1 на его зеркальное отображение с индексом -2 и так далее, пока не получите перевернутый список.

Вот представление всего процесса:

Reverse Lists in Python

Чтобы перевести этот процесс в код, вы можете использовать for цикл с объектом range в первой половине списка, который вы можете получить с помощью len(digits) // 2. Затем вы можете использовать оператор параллельного присваивания для замены элементов, например, следующим образом:

>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> for i in range(len(digits) // 2):
...     digits[i], digits[-1 - i] = digits[-1 - i], digits[i]
...

>>> digits
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]


Этот цикл выполняет итерацию по объекту range, который переходит от 0 к len(digits) // 2. Каждая итерация заменяет элемент из первой половины списка на его зеркальный аналог во второй половине. Выражение -1 - i, содержащееся в операторе индексации [], гарантирует доступ к зеркальному элементу. Вы также можете использовать выражение -1 * (i + 1) для получения соответствующего зеркального индекса.

Помимо описанного выше алгоритма, который использует преимущества подстановки индекса, существует несколько различных способов изменения списков вручную. Например, вы можете использовать .pop() и .insert() следующим образом:

>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> for i in range(len(digits)):
...     last_item = digits.pop()
...     digits.insert(i, last_item)
...

>>> digits
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]


В цикле вы вызываете .pop() для исходного списка без аргументов. Этот вызов удаляет и возвращает последний элемент в списке, поэтому вы можете сохранить его в last_item. Затем .insert() перемещает last_item на позицию по индексу i.

Например, первая итерация удаляет 9 из правого конца списка и сохраняет его в last_item. Затем она вставляет 9 в индекс 0. Следующая итерация берет 8 и перемещает его в индекс 1, и так далее. В конце цикла вы получите перевернутый список.

Создание перевернутых списков

Если вы хотите создать обратную копию существующего списка в Python, то вы можете использовать reversed(). Используя список в качестве аргумента, reversed() возвращает итератор, который возвращает элементы в обратном порядке:

>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> reversed_digits = reversed(digits)
>>> reversed_digits
<list_reverseiterator object at 0x7fca9999e790>

>>> list(reversed_digits)
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]


В этом примере вы вызываете reversed() с digits в качестве аргумента. Затем вы сохраняете результирующий итератор в reversed_digits. Вызов list() использует итератор и возвращает новый список, содержащий те же элементы, что и digits, но в обратном порядке.

Важно отметить, что при использовании reversed() не создается копия входного списка, поэтому изменения в нем влияют на результирующий итератор:

>>> fruits = ["apple", "banana", "orange"]

>>> reversed_fruit = reversed(fruits)  # Get the iterator
>>> fruits[-1] = "kiwi"  # Modify the last item
>>> next(reversed_fruit)  # The iterator sees the change
'kiwi'


В этом примере вы вызываете reversed(), чтобы получить соответствующий итератор для элементов в fruits. Затем вы изменяете последний результат. Это изменение влияет на итератор. Вы можете подтвердить это, позвонив по телефону next() чтобы получить первый товар в reversed_fruit.

Если вам нужно получить копию fruits с помощью reversed(), то вы можете позвонить list():

>>> fruits = ["apple", "banana", "orange"]

>>> list(reversed(fruits))
['orange', 'banana', 'apple']


Как вы уже знаете, вызов list() использует итератор, который является результатом вызова reversed(). Таким образом, вы создаете новый список как обратную копию исходного.

В Python 2.4 добавлен reversed() универсальный инструмент для облегчения обратной итерации над последовательностями, как указано в ОПТОСОЗ 322. В общем, reversed() может принимать любые объекты, которые реализуют .__reversed__() метод или поддерживают протокол последовательности, состоящий из двух специальных методов, .__len__() и .__getitem__(). Итак, reversed() не ограничивается списками:

>>> list(reversed(range(10)))
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

>>> list(reversed("Python"))
['n', 'o', 'h', 't', 'y', 'P']


Здесь вместо списка вы передаете объект range и строку в качестве аргументов reversed(). Функция выполняет свою работу должным образом, и вы получаете обратную версию входных данных.

Еще один важный момент, который следует подчеркнуть, заключается в том, что вы не можете использовать reversed() с произвольными итераторами:

>>> digits = iter([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

>>> reversed(digits)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'list_iterator' object is not reversible


В этом примере, iter() создает итератор для вашего списка чисел. Когда вы вызываете reversed() на digits, вы получаете TypeError.

Итераторы реализуют .__next__() специальный метод для просмотра базовых данных. Ожидается, что они также будут реализовывать .__iter__() специальный метод, возвращающий текущий экземпляр итератора. Однако ожидается, что они не будут реализовывать ни .__reversed__(), ни протокол последовательности. Таким образом, reversed() для них не работает. Если вам когда-нибудь понадобится изменить итератор подобным образом, вам следует сначала преобразовать его в список, используя list().

Еще один момент, на который следует обратить внимание, заключается в том, что вы не можете использовать reversed() с неупорядоченными повторяемыми:

>>> digits = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

>>> reversed(digits)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'set' object is not reversible


В этом примере, когда вы пытаетесь использовать reversed() с объектом set, вы получаете TypeError. Это происходит потому, что наборы не упорядочивают свои элементы, поэтому Python не знает, как их изменить.

Переворачивание Списков С Помощью Нарезки

Начиная с версии Python 1.4, синтаксис нарезки имеет третий аргумент, который называется step. Однако этот синтаксис изначально не работал со встроенными типами, такими как списки, кортежи и строки. Python 2.3 расширил синтаксис до встроенных типов, поэтому вы можете использовать step с их сейчас. Вот полный синтаксис нарезки:

a_list[start:stop:step]


Этот синтаксис позволяет извлекать все элементы в a_list из start в stop − 1 с помощью step. Третий индекс, step, по умолчанию равен 1, поэтому при обычной операции нарезки элементы извлекаются слева направо:

>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> digits[1:5]
[1, 2, 3, 4]


С помощью [1:5] вы получаете элементы из индекса 1 в индекс 5 - 1. Элемент с индексом, равным stop, никогда не включается в конечный результат. Эта нарезка возвращает все элементы в целевом диапазоне, потому что step по умолчанию равно 1.

Примечание: Вы можете опустить второе двоеточие (:) в операторе нарезки, если значение по умолчанию (1) соответствует вашим текущим потребностям.

Если вы используете другой step, то при нарезке будет отображаться столько элементов, сколько соответствует значению step:

>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> digits[0::2]
[0, 2, 4, 6, 8]

>>> digits[::3]
[0, 3, 6, 9]


В первом примере [0::2] извлекает все элементы из индекса 0 до конца индекса digits, каждый раз перепрыгивая через два элемента. Во втором примере нарезка перемещается по 3 элементам по мере продвижения. Если вы не указываете значения start и stop, то для них устанавливаются значения 0 и длина целевой последовательности соответственно.

Если вы установите для step значение -1, то получите фрагмент с элементами в обратном порядке:

>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> # Set step to -1
>>> digits[len(digits) - 1::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

>>> digits
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]


Это разбиение возвращает все элементы из правого конца списка (len(digits) - 1) обратно в левый конец, потому что вы опускаете второй индекс. Остальная часть волшебства в этом примере заключается в использовании значения -1 для step. При выполнении этого трюка вы получаете копию исходного списка в обратном порядке, не затрагивая входные данные.

Если вы полностью полагаетесь на неявные индексы, то синтаксис нарезки становится короче, понятнее и менее подвержен ошибкам:

>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> # Rely on default index values
>>> digits[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]


Здесь вы просите Python предоставить вам полный список ([::-1]), но просматриваете все элементы от начала до конца, устанавливая для step значение -1. Это довольно изящно, но reversed() более эффективно с точки зрения времени выполнения и использования памяти. Это также более читабельно и наглядно. Поэтому эти моменты следует учитывать в вашем коде.

Другим способом создания обратной копии существующего списка является использование slice(). Подпись этой встроенной функции выглядит следующим образом:

slice(start, stop, step)


Эта функция работает аналогично оператору индексирования. Он принимает три аргумента, значение которых аналогично тем, которые используются в операторе slicing, и возвращает объект slice, представляющий набор индексов, возвращаемых range(start, stop, step). Это звучит сложно, поэтому вот несколько примеров того, как работает slice():

>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> slice(0, len(digits))
slice(0, 10, None)

>>> digits[slice(0, len(digits))]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> slice(len(digits) - 1, None, -1)
slice(9, None, -1)

>>> digits[slice(len(digits) - 1, None, -1)]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]


Первый вызов slice() эквивалентен [0:len(digits)]. Второй вызов работает так же, как и [len(digits) - 1::-1]. Вы также можете имитировать нарезку [::-1] с помощью slice(None, None, -1). В этом случае передача None в start и stop означает, что вам нужен фрагмент от начала до конца целевой последовательности.

Примечание: По сути, при разделении литералов создаются slice объектов. Итак, когда вы опускаете индекс, как в [::-1], это работает так, как если бы вы передавали None соответствующему аргументу при вызове slice().

Вот как вы можете использовать slice() для создания обратной копии существующего списка:

>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> digits[slice(None, None, -1)]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]


Объект slice извлекает все элементы из digits, начиная с правого конца и заканчивая левым, и возвращает перевернутую копию целевого списка.

Создание перевернутых списков вручную

Итак, вы ознакомились с несколькими инструментами и техниками, позволяющими либо изменять списки на месте, либо создавать обратные копии существующих списков. В большинстве случаев эти инструменты и методы являются наиболее подходящими, когда дело доходит до изменения списков в Python. Однако, если вам когда-нибудь понадобится перевернуть списки вручную, вам будет полезно понять логику, лежащую в основе этого процесса.

В этом разделе вы узнаете, как изменять списки Python с помощью циклов, рекурсии и расширений. Идея заключается в том, чтобы получить список и создать его копию в обратном порядке.

Использование цикла

Первый метод, который вы будете использовать для изменения списка, включает в себя цикл for и объединение списка с помощью символа плюс (+):

>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> def reversed_list(a_list):
...     result = []
...     for item in a_list:
...         result = [item] + result
...     return result
...

>>> reversed_list(digits)
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]


Каждая итерация цикла for берет следующий элемент из a_list и создает новый список, который получается в результате объединения [item] и result, который изначально содержит пустой список. Вновь созданному списку присваивается значение result. Эта функция не изменяет a_list.

Примечание: В приведенном выше примере используется расточительный метод, поскольку он создает несколько списков только для того, чтобы выбросить их на следующей итерации.

Вы также можете воспользоваться .insert() для создания перевернутых списков с помощью цикла:

>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> def reversed_list(a_list):
...     result = []
...     for item in a_list:
...         result.insert(0, item)
...     return result
...

>>> reversed_list(digits)
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]


Вызов .insert() внутри цикла вставляет последующие элементы с индексом 0, равным result. В конце цикла вы получите новый список с элементами a_list в обратном порядке.

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

Использование рекурсии

Вы также можете использовать рекурсию для изменения списков. Рекурсия - это когда вы определяете функцию, которая вызывает саму себя. Это создает цикл, который может стать бесконечным, если вы не предоставите базовый вариант , который выдает результат без повторного вызова функции.

Базовый регистр необходим для завершения рекурсивного цикла. Что касается реверсивных списков, базовый регистр будет достигнут, когда рекурсивные вызовы дойдут до конца входного списка. Вам также необходимо определить рекурсивный регистр, который приводит все последующие регистры к базовому регистру и, следовательно, к концу цикла.

Вот как вы можете определить рекурсивную функцию для возврата обратной копии данного списка:

>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> def reversed_list(a_list):
...     if len(a_list) == 0:  # Base case
...         return a_list
...     else:
...         # print(a_list)
...         # Recursive case
...         return reversed_list(a_list[1:]) + a_list[:1]
...

>>> reversed_list(digits)
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]


Внутри reversed_list() вы сначала проверяете базовый вариант, в котором список ввода пуст, и возвращаете функцию. Предложение else предоставляет рекурсивный вариант, который является вызовом самого reversed_list(), но с фрагментом исходного списка, a_list[1:]. Этот фрагмент содержит все элементы из a_list, за исключением первого элемента, который затем добавляется в виде списка из одного элемента (a_list[:1]) к результату рекурсивного вызова.

Примечание: В рекурсивном случае вы можете заменить a_list[:1] на [a_list[0]], чтобы получить аналогичный результат.

Прокомментированный вызов print() в начале предложения else - это просто трюк, предназначенный для того, чтобы показать, как последующие вызовы сокращают список входных данных до базового варианта. Продолжайте и раскомментируйте строку, чтобы посмотреть, что получится!

Использование понимания списка

Если вы работаете со списками в Python, то, вероятно, захотите рассмотреть возможность использования понимания списка. Этот инструмент довольно популярен в среде Python, поскольку он представляет собой питонический способ обработки списков.

Вот пример того, как использовать понимание списка для создания перевернутого списка:

>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> last_index = len(digits) - 1

>>> [digits[i] for i in range(last_index, -1, -1)]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]


Волшебство в понимании этого списка заключается в вызове range(). В этом случае range() возвращает индексы из len(digits) - 1 обратно в 0. Это заставляет цикл понимания выполнять итерацию по элементам в digits в обратном порядке, создавая в процессе новый перевернутый список.

Перебор списков в обратном порядке

На данный момент вы узнали, как создавать перевернутые списки, а также как изменять существующие списки на месте, либо используя инструменты, специально разработанные для выполнения этой задачи, либо используя свои собственные решения, написанные вручную.

При повседневном программировании вы можете обнаружить, что перебор существующих списков и последовательностей в обратном порядке, обычно известный как обратная итерация, является довольно распространенным требованием. Если это ваш случай, то у вас есть несколько вариантов. В зависимости от ваших конкретных потребностей вы можете использовать:

  • Встроенная функция reversed()
  • Оператор нарезки, [::]
  • Специальный метод .__reversed__()

В следующих нескольких разделах вы узнаете обо всех этих параметрах и о том, как они могут помочь вам выполнять итерацию по спискам в обратном порядке.

Встроенная функция reversed()

Первым способом выполнения итерации по списку в обратном порядке может быть использование reversed(). Эта встроенная функция была специально разработана для поддержки обратной итерации. Используя список в качестве аргумента, он возвращает итератор, который возвращает элементы входного списка в обратном порядке.

Вот как вы можете использовать reversed() для перебора элементов в списке в обратном порядке:

>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> for digit in reversed(digits):
...     print(digit)
...
9
8
7
6
5
4
3
2
1
0


Первое, на что следует обратить внимание в этом примере, это то, что цикл for легко читается. Название reversed() четко выражает его назначение, а тонкие детали указывают на то, что функция не вызывает никаких побочных эффектов. Другими словами, он не изменяет список ввода.

Цикл также эффективен с точки зрения использования памяти, поскольку reversed() возвращает итератор, который выдает элементы по запросу, не сохраняя их все в памяти одновременно. Опять же, следует отметить тонкую деталь: если список входных данных изменяется во время итерации, то итератор видит изменения.

Оператор нарезки, [::-1]

Второй подход к обратной итерации заключается в использовании расширенного синтаксиса нарезки, который вы видели ранее. Этот синтаксис никак не способствует повышению эффективности использования памяти, красоты или ясности. Тем не менее, это обеспечивает быстрый способ просмотра обратной копии существующего списка без риска быть затронутым изменениями в исходном списке.

Вот как вы можете использовать [::-1] для перебора копии существующего списка в обратном порядке:

>>> digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> for digit in digits[::-1]:
...     print(digit)
...
9
8
7
6
5
4
3
2
1
0


Когда вы разрезаете список, как в этом примере, вы создаете обратную копию исходного списка. Изначально оба списка содержат ссылки на одну и ту же группу элементов. Однако, если вы присвоите новое значение данному элементу в исходном списке, как в digits[0] = "zero", ссылка изменится и будет указывать на новое значение. Таким образом, изменения во входном списке не повлияют на копию.

Примечание: По сравнению с расширенной нарезкой, reversed() более удобочитаем, выполняется быстрее и занимает значительно меньше памяти. Однако на это влияют изменения в списке ввода.

Вы можете воспользоваться преимуществами такого рода нарезки, чтобы безопасно изменять исходный список, одновременно перебирая его старые элементы в обратном порядке. Например, предположим, что вам нужно перебрать список чисел в обратном порядке и заменить каждое число его квадратичным значением. В этом случае вы можете сделать что-то вроде этого:

>>> numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> for i, number in enumerate(numbers[::-1]):
...     numbers[i] = number ** 2
...

>>> # Square values in reverse order
>>> numbers
[81, 64, 49, 36, 25, 16, 9, 4, 1, 0]


Здесь цикл повторяется по обратной копии numbers. Вызов функции enumerate() предоставляет индексы, основанные на возрастании нуля, для каждого элемента в обратной копии. Это позволяет изменять numbers во время итерации. Затем цикл изменяет numbers, заменяя каждый элемент его квадратным значением. В результате numbers содержит квадратные значения в обратном порядке.

Специальный метод .__reversed__()

В списках Python реализован специальный метод, называемый .__reversed__(), который позволяет выполнять обратную итерацию. Этот метод обеспечивает логику, лежащую в основе reversed(). Другими словами, вызов reversed() со списком в качестве аргумента запускает неявный вызов .__reversed__() для входного списка.

Этот специальный метод возвращает итератор для элементов текущего списка в обратном порядке. Однако .__reversed__() не предназначен для прямого использования. В большинстве случаев вы будете использовать его для оснащения своих собственных классов возможностями обратной итерации.

Например, предположим, что вы хотите выполнить итерацию по диапазону чисел с плавающей запятой. Вы не можете использовать range(), поэтому вы решили создать свой собственный класс, соответствующий этому конкретному варианту использования. В итоге вы получаете класс, подобный этому:

# float_range.py

class FloatRange:
    def __init__(self, start, stop, step=1.0):
        if start >= stop:
            raise ValueError("Invalid range")
        self.start = start
        self.stop = stop
        self.step = step

    def __iter__(self):
        n = self.start
        while n < self.stop:
            yield n
            n += self.step

    def __reversed__(self):
        n = self.stop - self.step
        while n >= self.start:
            yield n
            n -= self.step


Этот класс не идеален. Это всего лишь ваша первая версия. Однако он позволяет выполнять итерацию по интервалу чисел с плавающей запятой, используя фиксированное значение приращения step. В вашем классе, .__iter__() обеспечивает поддержку обычной итерации, а .__reversed__() поддерживает обратную итерацию.

Чтобы использовать FloatRange, вы можете сделать что-то вроде этого:

>>> from float_range import FloatRange

>>> for number in FloatRange(0.0, 5.0, 0.5):
...     print(number)
...
0.0
0.5
1.0
1.5
2.0
2.5
3.0
3.5
4.0
4.5


Класс поддерживает обычную итерацию, которая, как уже упоминалось, обеспечивается .__iter__(). Теперь вы можете попробовать выполнить итерацию в обратном порядке, используя reversed():

>>> from float_range import FloatRange

>>> for number in reversed(FloatRange(0.0, 5.0, 0.5)):
...     print(number)
...
4.5
4.0
3.5
3.0
2.5
2.0
1.5
1.0
0.5
0.0


В этом примере reversed() использует вашу реализацию .__reversed__() для обеспечения функциональности обратной итерации. Таким образом, у вас есть работающий итератор с плавающей запятой.

Реверсирование списков Python: Краткое изложение

На данный момент вы многое узнали о том, как изменять списки с помощью различных инструментов и техник. Вот таблица, в которой обобщены наиболее важные моменты, которые вы уже рассмотрели:

Feature .reverse() reversed() [::-1] Loop List Comp Recursion
Modifies the list in place ✔/❌
Creates a copy of the list ✔/❌
Is fast
Is universal

Краткое ознакомление с этим обзором позволит вам решить, какой инструмент или технику использовать при замене существующих списков, создании обратных копий существующих списков или повторном просмотре списков в обратном порядке.

Сортировка списков Python в обратном порядке

Еще один интересный вариант, когда дело доходит до изменения списков в Python, - это использовать .sort() и sorted() для их сортировки в обратном порядке. Чтобы сделать это, вы можете передать True в соответствующий аргумент reverse.

Примечание: Чтобы глубже понять, как использовать .sort() и sorted(), ознакомьтесь с Как использовать sorted() и .sort() в Python..

Цель .sort() - отсортировать элементы списка. Сортировка выполняется на месте, поэтому новый список не создается. Если вы зададите для аргумента ключевого слова reverse значение True, то получите список, отсортированный в порядке убывания или обратном порядке:

>>> digits = [0, 5, 7, 3, 4, 9, 1, 6, 3, 8]

>>> digits.sort(reverse=True)
>>> digits
[9, 8, 7, 6, 5, 4, 3, 3, 1, 0]


Теперь ваш список полностью отсортирован, а также в обратном порядке. Это очень удобно, когда вы работаете с некоторыми данными и вам нужно отсортировать их и изменить порядок в обратном порядке одновременно.

С другой стороны, если вы хотите выполнить итерацию по отсортированному списку в обратном порядке, то вы можете использовать sorted(). Эта встроенная функция возвращает новый список, содержащий все элементы входного итерационного параметра по порядку. Если вы передадите True в его аргумент ключевого слова reverse, то получите обратную копию исходного списка:

>>> digits = [0, 5, 7, 3, 4, 9, 1, 6, 3, 8]

>>> sorted(digits, reverse=True)
[9, 8, 7, 6, 5, 4, 3, 3, 1, 0]

>>> for digit in sorted(digits, reverse=True):
...     print(digit)
...
9
8
7
6
5
4
3
3
1
0


Аргумент reverse для sorted() позволяет сортировать повторяющиеся элементы в порядке убывания, а не в порядке возрастания. Итак, если вам нужно создавать отсортированные списки в обратном порядке, то sorted() для вас.

Заключение

Переворачивание и работа со списками в обратном порядке может быть довольно распространенной задачей в вашей повседневной работе в качестве Python программист. В этом руководстве вы воспользовались несколькими инструментами и техниками Python, чтобы изменить свои списки и управлять ими в обратном порядке.

В этом руководстве вы узнали, как:

  • Измените местами свои списки , используя .reverse() и другие методы
  • Используйте reversed() и нарезку для создания обратных копий ваших списков
  • Используйте итерацию, повторения и рекурсию для создания обратных списков
  • Выполните итерацию по вашим спискам в обратном порядке
  • Отсортируйте списков в обратном порядке, используя .sort() и sorted()

Все эти знания помогут вам улучшить свои навыки работы со списками. Они предоставляют вам необходимые инструменты для повышения квалификации при работе со списками на Python.

<статус завершения article-slug="python-обратный список" class="btn-group mb-0" data-api-article-bookmark-url="/api/v1/articles/python-обратный список/bookmark/" data-api-article-завершение-status-url="/api/v1/articles/python-обратный список/завершение_статуса/"> <кнопка поделиться bluesky-text="Интересная статья на #Python от @realpython.com :" email-body="Ознакомьтесь с этой статьей о Python:%0A%0AReverse Списки Python: Beyond .reverse() и reversised()" email-subject="Статья о Python для вас" twitter-текст="Интересная статья о #Python от @realpython:" url="https://realpython.com/python-reverse-list /" url-title="Обратные списки Python: за пределами .reverse() и reversed()"> Back to Top