Подробное руководство по индексам и срезам в Python
Материал дает понимание того, как связан индекс элемента и срез последовательности, объясняется работа с объектом среза и его применение на практике.
Содержание:
- Введение в индексы и срезы;
- Объект среза slice() ;
- Значения по умолчанию;
- Особый случай среза: копия последовательности;
- Примеры часто используемые срезов;
- Метод среза .indexes ;
- Собственные классы с возможностью применения срезов;
- Получение среза последовательности sequence[i:j] ;
- Получение среза с заданным шагом sequence[i:j:k] ;
- Замена части списка операцией среза;
- Замена части списка срезом c заданным шагом;
- Удаление части списка операцией среза;
- Удаление части списка срезом с заданным шагом
Введение в индексы и срезы.
В Python некоторые объекты, такие как строки или списки, можно нарезать. Например, можно получить первый элемент списка или строку с помощью индекса элемента:
>>> my_list = [1,2,3] >>> my_list[0] # 1 >>> my_string = "Python" >>> my_string[0] # P
Python использует квадратные скобки [ и ] для доступа к отдельным элементам объектов, которые можно разбить на части. Внутри этих квадратных скобок можно указать нечто большее, чем просто доступ к отдельным элементам.
Python поддерживает указание отрицательных индексов, их можно использовать следующим образом:
>>> my_list = list("Python") >>> my_list[-1]
Выражение my_list[-1] представляет последний элемент списка, my_list[-2] представляет предпоследний элемент и так далее.
Что делать, если нужно извлечь более одного элемента последовательности? Например, необходимо извлечь все от начала до конца, за исключением самого последнего элемента:
>>> my_list = list("Python") >>> my_list[0:-1]
Или, если нужен каждый четный элемент списка, то есть элемент 0, 2 и т. д.? Для этого нужно перейти от первого элемента к последнему, но пропустить каждый второй элемент. Например:
>>> my_list = list("Python") >>> my_list[0:len(my_list):2] # ['P', 't', 'o']
Объект среза slice() .
За кулисами, индекс, который используется для доступа к отдельным элементам последовательности представляет собой объект среза slice() принимающий три аргумента: slice(start, stop, step) .
Проверим это утверждение:
>>> my_list = list("Python") >>> start = 0 >>> stop = len(my_list) >>> step = 2 # объект среза >>> slice_obj = slice(start, stop, step) # сравниваем >>> my_list[start:stop:step] == my_list[slice_obj] # True
Примечание: буква P является первым элементом в списке ( list(«Python») ), поэтому она индексируется как 0. Список имеет длину 6, и, следовательно, первый элемент также может быть проиндексирован как -6.
Если использовать начало start и конец stop объекта среза, то каждый элемент между этими числами покрывается срезом. Некоторые примеры:
>>> my_string = "Python" >>> my_string[0:1] # P >>> my_string[0:5] # Pytho
Это способ запомнить, что начальное значение является инклюзивным, а конечное — исключающим.
Значения по умолчанию.
В большинстве случаев приходится делить список:
- начиная с 0 (первый элемент последовательности);
- с захватом нужного последнего элемента;
- с определенным шагом.
Следовательно, значения по умолчанию можно опустить и использовать синтаксис : :
>>> my_list = list("Python") >>> my_list[0:4] == my_list[:4] # True # используем шаг 2 >>> my_list[0:len(my_list):2] == my_list[::2] # True
Технически, всякий раз, когда опускается число между двоеточиями, пропущенные числа будут иметь значение None .
И, в свою очередь, объект slice() заменит None на:
- 0 для начального значения;
- len(list) для конечного значения;
- 1 для значения шага.
Но, если значение шага отрицательное, то числа заменяются на:
- -1 для начального значения;
- -len(list) — 1 для конечного значения.
Например, ‘Python'[::-1] технически совпадает с ‘Python'[-1:-7:-1]
Особый случай среза: копия последовательности.
Существует специальный случай для среза, который можно использовать в качестве поверхностного копирования. Если использовать только значения по умолчанию, т. е. my_list[:] , то это выражение создаст точно такие же элементы:
>>> my_list = list("Python") >>> my_list_2 = my_list[:] >>> my_list==my_list_2 # True
Элементы в списке действительно совпадают. Однако новый объект списка не является ссылкой на оригинал. Можно проверить это утверждение, используя встроенный идентификатор:
>>> id(my_list) # 139967020891648 >>> id(my_list_2) # 139967018223424
Обратите внимание, что каждая операция среза возвращает новый объект. Копия последовательности создается при использовании только [:] .
Пример, иллюстрирующий разницу:
>>> a = list("Python") # ссылка на оригинал списка >>> b = a >>> a[-1] = "N" >>> a # ['P', 'y', 't', 'h', 'o', 'N'] >>> b # ['P', 'y', 't', 'h', 'o', 'N'] >>> a = list("Python") # копия оригинала списка >>> b = a[:] >>> a[-1] = "N" >>> a # ['P', 'y', 't', 'h', 'o', 'N'] >>> b # ['P', 'y', 't', 'h', 'o', 'n']
Примеры часто используемые срезов:
- [:] — копия последовательности;
- [::2] — четные элементы последовательности начиная с первого;
- [1::2] — нечетные элементы последовательности начиная со второго;
- [1:] — все элементы, кроме первого;
- [:-1] — все элементы, кроме последнего;
- [1:-1] — все элементы, кроме первого и последнего;
- [::-1] — все элементы в обратном порядке (реверс последовательности);
- [-2:0:-1] — все элементы, кроме первого и последнего, в обратном порядке;
- [-2:0:-2] — каждый второй элемент, кроме первого и последнего, в обратном порядке;
Метод среза .indices .
Каждый объект slice() в Python имеет метод slice.indices() . Этот метод возвращает кортеж (start, end, step) , с помощью которой можно перестроить цикл, эквивалентный операции среза. Звучит сложно? Начнем разбираться с последовательности:
>>> sequence = list("Python")
Затем создадим объект slice() . Например возьмем каждый второй элемент, т.е. sequence[::2] .
# эквивалентно `[::2]` >>> my_slice = slice(None, None, 2)
Так как в качестве некоторых аргументов используется None , то объект slice() должен вычислять фактические значения индекса на основе длины последовательности. Следовательно, чтобы получить кортеж индексов, необходимо передать длину последовательности методу slice.indices() , например:
>>> indices = my_slice.indices(len(sequence)) >>> indices # (0, 6, 2)
Теперь можно воссоздать цикл следующим образом:
sequence = list("Python") start, stop, step = (0, 6, 2) i = start while i != stop: print(sequence[i]) i = i+step
Этот цикл позволяет получить доступ к тем же элементам последовательности, что и сам срез.
Собственные классы с возможностью применения срезов.
Python не был бы Python, если бы невозможно было использовать объект среза в своих собственных классах. Более того, срезы не обязательно должны быть числовыми значениями. Например, можно создать адресную книгу, которую потом можно нарезать по алфавитным индексам.
import string class AddressBook: def __init__(self): self.addresses = [] def add_address(self, name, address): self.addresses.append((name, address)) def get_addresses_by_first_letters(self, letters): letters = letters.upper() return [(name, address) for name, address in self.addresses if any(name.upper().startswith(letter) for letter in letters)] def __getitem__(self, key): if isinstance(key, str): return self.get_addresses_by_first_letters(key) if isinstance(key, slice): start, stop, step = key.start, key.stop, key.step letters = (string.ascii_uppercase[string.ascii_uppercase.index(start):string.ascii_uppercase.index(stop)+1:step]) return self.get_addresses_by_first_letters(letters) address_book = AddressBook() address_book.add_address("Sherlock Holmes", "221B Baker St., London") address_book.add_address("Wallace and Gromit", "62 West Wallaby Street, Wigan, Lancashire") address_book.add_address("Peter Wimsey", "110a Piccadilly, London") address_book.add_address("Al Bundy", "9764 Jeopardy Lane, Chicago, Illinois") address_book.add_address("John Dolittle", "Oxenthorpe Road, Puddleby-on-the-Marsh, Slopshire, England") address_book.add_address("Spongebob", "124 Conch Street, Bikini Bottom, Pacific Ocean") address_book.add_address("Hercule Poirot", "Apt. 56B, Whitehaven Mansions, Sandhurst Square, London W1") address_book.add_address("Bart Simpson", "742 Evergreen Terrace, Springfield, USA") print(string.ascii_uppercase) print(string.ascii_uppercase.index("A")) print(string.ascii_uppercase.index("Z")) print(address_book["A"]) print(address_book["B"]) print(address_book["S"]) print(address_book["A":"H"])
Разбираемся в созданном классе AddressBook .
- Метод get_addresses_by_first_letters() : Этот метод фильтрует все адреса, принадлежащие имени, которые начинаются с любой буквы в аргументе letters . Во-первых, эта функция нечувствительна к регистру, так как преобразует буквы в верхний регистр. Затем используется генератор списка поверх внутреннего списка адресов. Условие внутри генератора списка проверяет, соответствует ли какая-либо из предоставленных букв первой букве, соответствующее значению имени.
- Метод __getitem__ : Чтобы сделать объекты адресной книги доступными для использования среза, необходимо переопределить магический метод Python __getitem__ . Сначала проверяется, является ли ключ строкой. Это будет иметь место, если получаем доступ к объекту с помощью одной буквы в квадратных скобках, например так: address_book[‘A’] . Для этого тривиального случая можно просто вернуть любые адреса, имя которых начинается с данной буквы. Интересная часть, когда ключ является объектом среза. Например, этому условию будет соответствовать обращение типа address_book[‘A’:’H’] . Во-первых, идентифицируются все буквы в алфавитном порядке между буквами A и H . Модуль string перечисляет все латинские буквы в string.ascii_uppercase . Далее используется срез для извлечения букв между заданными буквами. Обратите внимание на +1 во втором параметре среза. Таким образом, гарантируется, что последняя буква является включающей, а не исключающей. После того, как определили все буквы в последовательности, используется метод get_addresses_by_first_letters() , о котором говорилось выше.
Что означают квадратные скобки в документации?
Часто в документации встречаются квадратные скобки, например _.get(object, path, [defaultValue]) — что они означают?
- Количеству голосов ▼
- Дата создания
06 апреля 2022
Таким образом в документации отмечают необязательные параметры, то есть на примере _.get(object, path, [defaultValue]) — этот метод можно вызвать как с двумя параметрами object и path , так и с тремя(добавляется defaultValue ). Третий параметр не обязательный, он указывает какое значение вернуть, если в объекте не будет значение в указанном пути:
const object = 'a': [ 'b': 'c': 3 > >] >; // Вызов с двумя параметрами: _.get(object, 'a[0].b.c'); // => 3 // Ещё один вызов с двумя параметрами: _.get(object, ['a', '0', 'b', 'c']); // => 3 // Вызов с тремя параметрами: _.get(object, 'a.b.c', 'default'); // => 'default'
Основы Python — кратко. Часть 3. Списки, кортежи, файлы.
Также следует заметить что это это, видимо, последний «простой урок», дальше я постараюсь углубиться во все аспекты программирования, которые мы прошли «по верхам» и продолжить более детально.
В общем, те кому не интересно — читают следующую новость, а остальных — прошу пройти .
Python для начинающих. Глава третья. «List, tuple, etc.»
Кортежи.
Кортежи (англ. tuple) используется для представления неизменяемой последовательности разнородных объектов. Они обычно записываются в круглых скобках, но если неоднозначности не возникает, то скобки можно опустить.
>>> t = (2, 2.05, "Hello") >>> t (2, 2.0499999999999998, 'Hello') >>> (a, b, c) = t >>> print a, b, c 2 2.05 Hello >>> z, y, x = t >>> print z, y, x 2 2.05 Hello >>> a=1 >>> b=2 >>> a,b=b,a >>> print a,b 2 1 >>> x = 12, >>> x (12,)
Как видно из примера, кортеж может быть использован и в левой части оператора присваивания. Значения из кортежа в левой части оператора присваивания связываются с аналогичными элементами правой части. Этот факт как раз и дает нам такие замечательные возможности как массовая инициализация переменных и возврат множества значений из функции одновременно. Последний пример демонстрирует создание кортежа из одного элмента (его часто называют синглтоном).
Списки
В Пайтоне отсутствуют массивы в традиционном понимании этого термина. Вместо них для хранения однородных (и не только) объектов используются списки. Они задаются тремя способами.
>>> a = [2, 2.25, "Python"] >>> a [2, 2.25, 'Python']
Преобразуем строку в список
>>> b = list("help") >>> b ['h', 'e', 'l', 'p']
Создание с помощью списковых включений. В данном случае мы берем кубы всех нечетных чисел от 0 до 19. Этому синтаксису я планирую посвятить отдельное занятие.
>>> c = [x ** 3 for x in range(20) if x%2==1] >>> c [1, 27, 125, 343, 729, 1331, 2197, 3375, 4913, 6859]
Для работы со списками определен ряд операторов и функций:
len(s) Длина последовательности s
x in s Проверка принадлежности элемента последовательности. В новых версиях Python можно проверять принадлежность подстроки строке. Возвращает True или False
x not in s = not x in s
s + s1 Конкатенация последовательностей
s*n или n*s Последовательность из n раз повторенной s. Если n < 0, возвращается пустая последовательность.
s[i] Возвращает i-й элемент s или len(s)+i-й, если i < 0
s[i:j:d] Срез из последовательности s от i до j с шагом d будет рассматриваться ниже
min(s) Наименьший элемент s
max(s) Наибольший элемент s
s[i] = x i-й элемент списка s заменяется на x
s[i:j:d] = t Срез от i до j (с шагом d) заменяется на (список) t
del s[i:j:d] Удаление элементов среза из последовательности
Кроме того, для списков определен ряд методов.
append(x) Добавляет элемент в конец последовательности
count(x) Считает количество элементов, равных x
extend(s) Добавляет к концу последовательности последовательность s
index(x) Возвращает наименьшее i, такое, что s[i] == x. Возбуждает исключение ValueError, если x не найден в s
insert(i, x) Вставляет элемент x в i-й промежуток
pop(i) Возвращает i-й элемент, удаляя его из последовательности
reverse() Меняет порядок элементов s на обратный
sort([cmpfunc]) Сортирует элементы s. Может быть указана своя функция сравнения cmpfunc
Для преобразования кортежа в список есть функция list, для обратной операции — tuple.
Об индексировании списков и выделении подпоследовательностей следует еще раз упомянуть отдельно (этот механизм работает аналогично и для строк). Для получения элемента используются квадратные скобки, в которых находится индекс элемента. Элементы нумеруются с нуля. Отрицательное значение индекса указывает на элементы с конца. Первый с конца списка (строки) элемент имеет индекс -1.
>>> s = [0, 1, 2, 3, 4] >>> print s[0], s[-1], s[3] 0 4 3 >>> s[2] = -2 >>> print s [0, 1, -2, 3, 4] >>> del s[2] >>> print s [0, 1, 3, 4]
Сложнее обстоят дела со срезами. Для получения срезов последовательности в Пайтоне принято указывать не номера элементов, а номера «промежутков» между ними. Перед первым элементом последовательности промежуток имеет индекс 0, перед вторым – 1 и так далее. Отрицательные значения отсчитывают элементы с конца строки.
В общем виде срез записывается в следующем виде:
список[начало: конец: шаг]
По умолчанию начало среза равно 0, конец среза равен len(список), шаг равен 1. Если шаг не указывается, второй символ «:» можно опустить.
С помощью среза можно указать подмножество для вставки списка в другой список, даже при нулевой длине. Это удобно для вставки списка в строго определенной позиции.
>>> l = range(12) >>> l [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] >>> l[1:3] [1, 2] >>> l[-1:] [11] >>> l[::2] [0, 2, 4, 6, 8, 10] >>> l[0:1]=[-1,-1,-1] >>> l [-1, -1, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] >>> del l[:3] >>> l [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
Словари
Словарь (хэш, предопределенный массив) – изменяемая структура данных, предназначенная для хранения элементов вида ключ: значение. Все легко показывается на примере.
>>> h1 = >>> h2 = >>> h3 = #Цикл по паре ключ-значение >>> for key, value in h1.items(): . print key, " ", value . 1 one 2 two 3 three #Цикл по ключам >>> for key in h2.keys(): . print key, " ", h2[key] . 0 zero 5 five #Цикл по значениям >>> for v in h3.values(): . print v . 2 3 1 #Добавление элементов из другого хеша >>> h1.update(h3) #Количество пар в хеше >>> len(h1) 6
Тип file
Объекты этого типа предназначены для работы с внешними данными. Чаще всего данному объекту соответствует файл на диске, но это далеко не всегда так. Файловые объекты должны поддерживать основные методы: read(), write(), readline(), readlines(), seek(), tell(), close() и т.п.
Следующий пример показывает копирование файла:
f1 = open("file1.txt", "r") f2 = open("file2.txt", "w") for line in f1.readlines(): f2.write(line) f2.close() f1.close()
(этот пример можно записать массой других способов, многие из которых сильно отличаются по оптимальности, но это тоже тема отдельного разговора)
В принципе, большинству функций абсолютно безразлично, передан им объект типа файл, или любой другой объект с такими же методами. Так, приведенный выше пример можно очень легко модифицировать для скачивания файла из Интерне, заменив в нем первую строку на следующий код.
import urllib f1 = urllib.urlopen("http://python.onego.ru")
Задачи:
— Разработать программу «массовой закачки» URL-ов из файла urls.txt
— Разработать программу, скачивающую страницу по указанному URL со всем ее содержимым.
— Написать программу, которая получив на входе произвольный список удалит из него все повторяющиеся элементы.
В каких случаях пишутся квадратные скобки в Python? [закрыт]
Хотите улучшить этот вопрос? Переформулируйте вопрос так, чтобы он был сосредоточен только на одной проблеме.
Закрыт 4 года назад .
В каких случаях пишутся квадратные скобки в Python?
Отслеживать
13.7k 12 12 золотых знаков 43 43 серебряных знака 75 75 бронзовых знаков
задан 16 янв 2019 в 18:06
Quiet Games Quiet Games
1 1 1 золотой знак 1 1 серебряный знак 2 2 бронзовых знака
В тех, где это допустимо по синтаксису и уместно в контексте решаемой задачи.
16 янв 2019 в 18:18
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Тогда, когда создается/используется список как тип данных, подробнее можешь почитать, загуглив «списки Python» или по ссылке.
Отслеживать
user262779
ответ дан 16 янв 2019 в 19:40
Артем Учуаткин Артем Учуаткин
11 1 1 бронзовый знак
В очереди проверок вам могут указать, что это ответ-ссылка. Я ответил «выглядит нормально», т.к. начало ответа пусть и кратко, но говорит про использование скобок в списках — из очереди проверок.
16 янв 2019 в 20:35
typing.Optional[typing.Dict[str, typing.List[int]]] немного не согласен с вами 🙂
16 янв 2019 в 20:40
@AK Спасибо большое 🙂
17 янв 2019 в 23:16
-
Важное на Мете
Похожие
Дизайн сайта / логотип © 2024 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2024.1.3.2953
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.