Функция Python range () (Руководство)

Функция Python range () (Руководство)

Встроенная функция Pythonrange удобна, когда вам нужно выполнить действие определенное количество раз. Как опытный Pythonista, вы, скорее всего, использовали его раньше. Но что это делает?

К концу этого руководства вы:

  • Понять, как работает функция Pythonrange

  • Знать, как реализации отличаются в Python 2 и Python 3

  • Видел несколько практических примеровrange()

  • Быть оборудованным, чтобы обойти некоторые из его ограничений

Давайте взломать!

Free Bonus:Click here to get our free Python Cheat Sheet, который показывает вам основы Python 3, такие как работа с типами данных, словарями, списками и функциями Python.

История функции Pythonrange()

Хотяrange() в Python 2 иrange() в Python 3 могут иметь одно и то же имя, это совершенно разные животные. Фактически,range() в Python 3 - это просто переименованная версия функции, которая называетсяxrange в Python 2.

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

Наличие огромных списков занимает много памяти, поэтому неудивительно, чтоxrange() заменилrange(), имя и все остальное. Вы можете узнать больше об этом решении и фонеxrange() противrange() вPEP 3100.

Note: PEP расшифровывается как Python Enhancement Proposal. PEP - это документы, которые могут охватывать широкий спектр тем, включая предлагаемые новые функции, стиль, управление и философию.

Естьa ton of them. PEP 1 объясняет, как они работают, и является отличным местом для начала.

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

Вот так!

Давай петля

Прежде чем мы углубимся в то, как работаетrange(), нам нужно взглянуть на то, как работает цикл. Цикл - этоkey computer science concept. Если вы хотите быть хорошим программистом, освоение циклов является одним из первых шагов, которые вам нужно сделать.

Вот пример цикла for в Python:

captains = ['Janeway', 'Picard', 'Sisko']

for captain in captains:
    print(captain)

Вывод выглядит так:

Janeway
Picard
Sisko

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

Хотя Star Trek великолепен и все такое, вы можете захотеть сделать больше, чем просто просмотреть список капитанов. Иногда вы просто хотите выполнить блок кода определенное количество раз. Петли могут помочь вам сделать это!

Попробуйте следующий код с числами, которые делятся на три:

numbers_divisible_by_three = [3, 6, 9, 12, 15]

for num in numbers_divisible_by_three:
    quotient = num / 3
    print(f"{num} divided by 3 is {int(quotient)}.")

Вывод этого цикла будет выглядеть так:

3 divided by 3 is 1.
6 divided by 3 is 2.
9 divided by 3 is 3.
12 divided by 3 is 4.
15 divided by 3 is 5.

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

Note: В этом последнем примере кода было строковое форматирование. Чтобы узнать больше по этой теме, вы можете проверитьPython String Formatting Best Practices иPython 3’s f-Strings: An Improved String Formatting Syntax (Guide).

Теперь, когда вы более знакомы с циклами, давайте посмотрим, как вы можете использоватьrange(), чтобы упростить себе жизнь.

Основы Pythonrange()

Так как же работает функция Pythonrange? Проще говоря,range() позволяет генерировать серию чисел в заданном диапазоне. В зависимости от того, сколько аргументов вы передаете в функцию, вы можете решить, где эта серия чисел будет начинаться и заканчиваться, а также насколько велика будет разница между одним числом и следующим.

Вот краткий обзорrange() в действии:

for i in range(3, 16, 3):
    quotient = i / 3
    print(f"{i} divided by 3 is {int(quotient)}.")

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

Note: Хотя в этом примере показано правильное использованиеrange(), обычно не одобряется слишком частое использованиеrange() в циклах for.

Например, следующее использованиеrange() обычно считается не Pythonic:

captains = ['Janeway', 'Picard', 'Sisko']

for i in range(len(captains)):
    print(captains[i])

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

Если вы хотите узнать больше, посмотритеHow to Make Your Python Loops More Pythonic.

Вы можете вызватьrange() тремя способами:

  1. range(stop) принимает один аргумент.

  2. range(start, stop) принимает два аргумента.

  3. range(start, stop, step) принимает три аргумента.

range(stop)

Когда вы вызываетеrange() с одним аргументом, вы получите серию чисел, которая начинается с0 и включает все целые числа до, но не включая, числа, которое вы указали какstopс.

Вот как это выглядит на практике:

for i in range(3):
    print(i)

Вывод вашего цикла будет выглядеть так:

0
1
2

Это подтверждается: у нас есть все целые числа от0 до3, но не включая его, число, которое вы указали какstop.

range(start, stop)

Когда вы вызываетеrange() с двумя аргументами, вы можете решить не только, где заканчивается последовательность чисел, но и где она начинается, поэтому вам не нужно начинать с0 все время. Вы можете использоватьrange() для генерации ряда чисел отA доB, используяrange(A, B). Давайте узнаем, как создать диапазон, начинающийся с1.

Попробуйте вызватьrange() с двумя аргументами:

for i in range(1, 8):
    print(i)

Ваш вывод будет выглядеть так:

1
2
3
4
5
6
7

Пока все хорошо: у вас есть все целые числа от1 (число, указанное вами какstart) до, но не включая8 (число, указанное вами какstopс).

Но если вы добавите еще один аргумент, вы сможете воспроизвести результат, который вы получили ранее, когда использовали список с именемnumbers_divisible_by_three.

range(start, stop, step)

Когда вы вызываетеrange() с тремя аргументами, вы можете выбрать не только, где последовательность чисел будет начинаться и останавливаться, но также насколько велика будет разница между одним числом и другим. Если вы не укажетеstep, тоrange() будет автоматически вести себя так, как если быstep был1.

Note:step может быть положительным или отрицательным числом, но не0:

>>>

>>> range(1, 4, 0)
Traceback (most recent call last):
  File "", line 1, in 
ValueError: range() arg 3 must not be zero

Если вы попытаетесь использовать0 в качестве шага, вы получите сообщение об ошибке.

Теперь, когда вы знаете, как использоватьstep, вы можете, наконец, вернуться к тому циклу, который мы видели ранее, с делением на3.

Попробуйте сами:

for i in range(3, 16, 3):
    quotient = i / 3
    print(f"{i} divided by 3 is {int(quotient)}.")

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

3 divided by 3 is 1.
6 divided by 3 is 2.
9 divided by 3 is 3.
12 divided by 3 is 4.
15 divided by 3 is 5.

Как вы видите в этом примере, вы можете использовать аргументstep для увеличения в сторону большего числа. Это называется приращением.

Приращение сrange()

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

for i in range(3, 100, 25):
    print(i)

Если вашstep равен25, то результат вашего цикла будет выглядеть так:

3
28
53
78

У вас есть диапазон чисел, каждое из которых больше предыдущего на25, указанное вамиstep.

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

Уменьшение сrange()

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

В следующем примере вашstep равен-2. Это означает, что вы будете уменьшать на2 для каждого цикла:

for i in range(10, -6, -2):
    print(i)

Вывод вашего декрементного цикла будет выглядеть так:

10
8
6
4
2
0
-2
-4

У вас есть диапазон чисел, каждое из которых меньше предыдущего на2,absolute value изstep, которое вы указали.

Самый питонический способ создать уменьшающийся диапазон - использоватьrange(start, stop, step). Но в Python есть встроенная функцияreversed. Если вы заключитеrange() внутрьreversed(), вы можете вывести целые числа в обратном порядке.

Попробуйте это:

for i in reversed(range(5)):
    print(i)

Вы получите это:

4
3
2
1
0

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

Note:reversed() также работает со строками. Вы можете узнать больше о функциональностиreversed() со строками вHow to Reverse a String in Python.

Расширенные примеры использования функции Pythonrange()

Теперь, когда вы знаете основы использованияrange(), пора копнуть глубже.

range() в основном используется для двух целей:

  1. Выполнение тела цикла for определенное количество раз

  2. Создание более эффективных итераций целых чисел, чем можно сделать с помощьюlists or tuples

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

Вот еще несколько моментов, которые следует учитывать при использовании диапазона.

range() - это тип в Python:

>>>

>>> type(range(3))

Вы можете получить доступ к элементам вrange() по индексу, как и со списком:

>>>

>>> range(3)[1]
1
>>> range(3)[2]
2

Вы даже можете использовать нотацию срезов вrange(), но вывод в REPL сначала может показаться немного странным:

>>>

>>> range(6)[2:5]
range(2, 5)

Хотя этот вывод может выглядеть странно, нарезкаrange() просто возвращает другойrange().

Тот факт, что вы можете получить доступ к элементамrange() по индексу и разрезатьrange(), подчеркивает важный факт:range() ленив, в отличие от списка, ноisn’t an iterator.

Плавающие иrange()

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

Слово на поплавках

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

Целое число (тип данныхint):

  • Целое число

  • Не включает десятичную точку

  • Может быть положительным, отрицательным или0

Число с плавающей запятой (тип данныхfloat):

  • Может быть любым числом с десятичной точкой

  • Может быть положительным или отрицательным

Попробуйте вызватьrange() с плавающей точкой и посмотрите, что произойдет:

for i in range(3.3):
    print(i)

Вы должны получить следующее сообщение об ошибке:

Traceback (most recent call last):
  File "", line 1, in 
TypeError: 'float' object cannot be interpreted as an integer

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

Использованиеrange() с NumPy

NumPy - это сторонняя библиотека Python. Если вы собираетесь использовать NumPy, первым делом проверьте, установлена ​​ли она у вас.

Вот как вы можете сделать это в своем REPL:

>>>

>>> import numpy

Если вы получилиModuleNotFoundError, то вам необходимо его установить. Для этого перейдите в командную строку и введитеpip install numpy.

После того, как он установлен, введите следующее:

import numpy as np

np.arange(0.3, 1.6, 0.3)

Это вернет это:

array([0.3, 0.6, 0.9, 1.2, 1.5])

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

import numpy as np

for i in np.arange(0.3, 1.6, 0.3):
    print(i)

Это вывод:

0.3
0.6
0.8999999999999999
1.2
1.5

Откуда взялся0.8999999999999999?

У компьютеров возникают проблемы с сохранением десятичных чисел с плавающей точкой в ​​двоичных числах с плавающей точкой. Это приводит к всевозможным неожиданным представлениям чисел.

Note: Чтобы узнать больше о том, почему возникают проблемы с десятичными знаками, вы можете проверитьthis article иPython docs.

Возможно, вы также захотите взглянуть наdecimal library, что немного снижает производительность и удобочитаемость, но позволяет точно представлять десятичные числа.

Другой вариант - использоватьround(), о котором вы можете узнать больше вHow to Round Numbers in Python. Имейте в виду, чтоround() имеет свои особенности, которые могут привести к неожиданным результатам!

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

В качестве альтернативы вы также можете использоватьnp.linspace(). По сути, он делает то же самое, но использует разные параметры. С помощьюnp.linspace() вы указываетеstart иend (оба включительно), а также длину массива (вместоstep).

Например,np.linspace(1, 4, 20) дает 20 чисел с равным интервалом:1.0, ..., 4.0. С другой стороны,np.linspace(0, 0.5, 51) дает0.00, 0.01, 0.02, 0.03, ..., 0.49, 0.50.

Note: Чтобы узнать больше, вы можете прочитатьLook Ma, No For-Loops: Array Programming With NumPy и этот удобныйNumPy reference.

Иди дальше и петля

Теперь вы понимаете, как использоватьrange() и как обходить его ограничения. У вас также есть представление о том, как эта важная функция развивалась между Python 2 и Python 3.

В следующий раз, когда вам нужно будет выполнить действие определенное количество раз, у вас будет все готово, чтобы замолчать!

Счастливого Pythoning!