Создайте пустой список определенного размера в Python
В этом посте мы обсудим, как создать пустой список заданного размера в Python.
Чтобы присвоить любое значение списку, используя оператор присваивания в позиции i , a[i] = x , размер списка должен быть не менее i+1 . В противном случае он поднимет IndexError , как показано ниже:
Решение состоит в том, чтобы создать пустой список None когда элементы списка заранее неизвестны. Это можно легко сделать, как показано ниже:
Приведенный выше код создаст список размеров 5 , где каждая позиция инициализируется None . None часто используется в Python для обозначения отсутствия значения.
Другой альтернативой для создания пустых списков заданного размера является использование генераторов списков:
Какое решение использовать?
Первое решение хорошо работает для нессылочных типов, таких как числа. Но в некоторых случаях вы можете столкнуться с ошибками ссылок. Например, [[]] * 5 приведет к повторению списка, содержащего один и тот же объект списка 5 раз.
Решение этой проблемы заключается в использовании списков, подобных этому:
Это все о создании пустого списка заданного размера в Python.
Также см:
Оценить этот пост
Средний рейтинг 4.9 /5. Подсчет голосов: 20
Голосов пока нет! Будьте первым, кто оценит этот пост.
Сожалеем, что этот пост не оказался для вас полезным!
Расскажите, как мы можем улучшить этот пост?
Спасибо за чтение.
Пожалуйста, используйте наш онлайн-компилятор размещать код в комментариях, используя C, C++, Java, Python, JavaScript, C#, PHP и многие другие популярные языки программирования.
Как мы? Порекомендуйте нас своим друзьям и помогите нам расти. Удачного кодирования
Как задать длину листа python
Большинство программ работает не с отдельными переменными, а с набором переменных. Например, программа может обрабатывать информацию об учащихся класса, считывая список учащихся с клавиатуры или из файла, при этом изменение количества учащихся в классе не должно требовать модификации исходного кода программы.
Раньше мы сталкивались с задачей обработки элементов последовательности, например, вычисляя наибольший элемент последовательности. Но при этом мы не сохраняли всю последовательность в памяти компьютера. Однако, во многих задачах нужно именно сохранять всю последовательность, например, если бы нам требовалось вывести все элементы последовательности в возрастающем порядке (“отсортировать последовательность”).
Для хранения таких данных можно использовать структуру данных, называемую в Питоне список (в большинстве же языков программирования используется другой термин “массив”). Список представляет собой последовательность элементов, пронумерованных от 0, как символы в строке. Список можно задать перечислением элементов списка в квадратных скобках, например, список можно задать так:
В списке Primes — 6 элементов, а именно: Primes[0] == 2 , Primes[1] == 3 , Primes[2] == 5 , Primes[3] == 7 , Primes[4] == 11 , Primes[5] == 13 . Список Rainbow состоит из 7 элементов, каждый из которых является строкой.
Длину списка, то есть количество элементов в нем, можно узнать при помощи функции len , например, len(Primes) == 6 .
В отличие от строк, элементы списка можно изменять, присваивая им новые значения.
Рассмотрим несколько способов создания и считывания списков. Прежде всего, можно создать пустой список (не содержащий элементов, длины 0), а в конец списка можно добавлять элементы при помощи метода append . Например, пусть программа получает на вход количество элементов в списке n , а потом n элементов списка по одному в отдельной строке. Вот пример входных данных в таком формате:
В этом примере создается пустой список, далее считывается количество элементов в списке, затем по одному считываются элементы списка и добавляются в его конец. То же самое можно записать, сэкономив переменную n :
Для списков целиком определены следующие операции: конкатенация списков (сложение списков, т. е. приписывание к одному списку другого) и повторение списков (умножение списка на число). Например:
В результате список c будет равен [1, 2, 3, 4, 5] , а список d будет равен [4, 5, 4, 5, 4, 5] . Это позволяет по-другому организовать процесс считывания списков: сначала считать размер списка и создать список из нужного числа элементов, затем организовать цикл по переменной i начиная с числа 0 и внутри цикла считывается i -й элемент списка:
Вывести элементы списка a можно одной инструкцией print(a) , при этом будут выведены квадратные скобки вокруг элементов списка и запятые между элементами списка. Такой вывод неудобен, чаще требуется просто вывести все элементы списка в одну строку или по одному элементу в строке. Приведем два примера, также отличающиеся организацией цикла:
Здесь в цикле меняется индекс элемента i , затем выводится элемент списка с индексом i .
В этом примере элементы списка выводятся в одну строку, разделенные пробелом, при этом в цикле меняется не индекс элемента списка, а само значение переменной (например, в цикле for elem in [‘red’, ‘green’, ‘blue’] переменная elem будет последовательно принимать значения ‘red’ , ‘green’ , ‘blue’ .
Последовательностями в Питоне являются строки, списки, значения функции range() (это не списки), и ещё кое-какие другие объекты.
Приведем пример, демонстрирующий использование цикла for в ситуации, когда из строки надо выбрать все цифры и сложить их в массив как числа.
2. Методы split и join
Элементы списка могут вводиться по одному в строке, в этом случае строку целиком можно считать функцией input() . После этого можно использовать метод строки split() , возвращающий список строк, которые получатся, если исходную строку разрезать на части по пробелам. Пример:
Если при запуске этой программы ввести строку 1 2 3 , то список a будет равен [‘1’, ‘2’, ‘3’] . Обратите внимание, что список будет состоять из строк, а не из чисел. Если хочется получить список именно из чисел, то можно затем элементы списка по одному преобразовать в числа:
Используя специальную магию Питона — генераторы — то же самое можно сделать в одну строку:
Объяснение того, как работает этот код, будет дано в следующем разделе. Если нужно считать список действительных чисел, то нужно заменить тип int на тип float .
У метода split() есть необязательный параметр, который определяет, какая строка будет использоваться в качестве разделителя между элементами списка. Например, вызов метода split(‘.’) вернет список, полученный разрезанием исходной строки по символам ‘.’ :
В Питоне можно вывести список строк при помощи однострочной команды. Для этого используется метод строки join . У этого метода один параметр: список строк. В результате возвращается строка, полученная соединением элементов переданного списка в одну строку, при этом между элементами списка вставляется разделитель, равный той строке, к которой применяется метод. Мы знаем, что вы не поняли предыдущее предложение с первого раза. Поэтому смотрите примеры:
Если же список состоит из чисел, то придется использовать еще тёмную магию генераторов. Вывести элементы списка чисел, разделяя их пробелами, можно так:
Впрочем, если вы не любитель тёмной магии, то вы можете достичь того же эффекта, используя цикл for .
3. Генераторы списков
Для создания списка, заполненного одинаковыми элементами, можно использовать оператор повторения списка, например:
Для создания списков, заполненных по более сложным формулам можно использовать генераторы: выражения, позволяющие заполнить список некоторой формулой. Общий вид генератора следующий:
где переменная — идентификатор некоторой переменной, последовательность — последовательность значений, который принимает данная переменная (это может быть список, строка или объект, полученный при помощи функции range ), выражение — некоторое выражение, как правило, зависящее от использованной в генераторе переменной, которым будут заполнены элементы списка.
Вот несколько примеров использования генераторов.
Создать список, состоящий из n нулей можно и при помощи генератора:
Создать список, заполненный квадратами целых чисел можно так:
Если нужно заполнить список квадратами чисел от 1 до n , то можно изменить параметры функции range на range(1, n + 1) :
Вот так можно получить список, заполненный случайными числами от 1 до 9 (используя функцию randrange из модуля random ):
А в этом примере список будет состоять из строк, считанных со стандартного ввода: сначала нужно ввести число элементов списка (это значение будет использовано в качестве аргумента функции range ), потом — заданное количество строк:
4. Срезы
Со списками, так же как и со строками, можно делать срезы. А именно:
A[i:j] срез из j-i элементов A[i] , A[i+1] , . A[j-1] .
A[i:j:-1] срез из i-j элементов A[i] , A[i-1] , . A[j+1] (то есть меняется порядок элементов).
A[i:j:k] срез с шагом k : A[i] , A[i+k] , A[i+2*k] . . Если значение k <0, то элементы идут в противоположном порядке.
Каждое из чисел i или j может отсутствовать, что означает “начало строки” или “конец строки”
Списки, в отличии от строк, являются изменяемыми объектами: можно отдельному элементу списка присвоить новое значение. Но можно менять и целиком срезы. Например:
Получится список, у которого вместо двух элементов среза A[2:4] вставлен новый список уже из трех элементов. Теперь список стал равен [1, 2, 7, 8, 9, 5] .
Получится список [40, 2, 30, 4, 20, 6, 10] . Здесь A[::-2] — это список из элементов A[-1] , A[-3] , A[-5] , A[-7] , которым присваиваются значения 10, 20, 30, 40 соответственно.
Если не непрерывному срезу (то есть срезу с шагом k , отличному от 1), присвоить новое значение, то количество элементов в старом и новом срезе обязательно должно совпадать, в противном случае произойдет ошибка ValueError .
list — списки
Список — это упорядоченная, изменяемая последовательность любых объектов языка Python.
Создание с помощью литералов []
Простейший способ создать список — перечислить его элементы через запятую и заключить их в квадратные скобки:
Если указать только квадратные скобки, то будет создан пустой список:
Квадратные скобки являются литералом спискового типа данных, то есть благодаря им интерпретатор Python может понять что перед ним находится именно список, а не какой-то другой тип данных. Кстати, создание списков именно таким образом может выполняться в многострочном варианте, что бывает очень удобно если вам необходимо создать матрицу:
Как нетрудно заметить, созданная только что матрица, по своей сути является списком, внутри которого находятся три вложенных списка. Вложение списков друг в друга бывает очень удобным не только для создания матриц, но и создания прямоугольных таблиц. В будущем, вам возможно придется работать с табличными базами данных, так вот, один из способов добавления целых таблиц или их фрагментов в базу данных, как раз и заключается в том, что они могут быть созданы в виде вложенных списков, например, вот так:
Создание с помощью генераторов списков
В некоторых случаях, когда необходимо создать очень большой список с элементами которые получаются с помощью простого правила, то гораздо удобнее создавать его не вручную, а с помощью генераторов списков:
Генераторы списков, довольно просты в использовании, к ним нужно просто привыкнуть. По сути, генераторы это просто вывернутые наизнанку циклы for и они вовсе не обязаны быть одномерными, т.е. генераторы вложенные друг в друга позволяют создавать списки вложенные в другие списки:
Функция list()
Еще один способ создания списков заключается в том чтобы использовать встроенную функцию list() . Если вызвать данную функцию без аргументов, то будет возвращен пустой список:
Если передать функции list любой итерируемый объект, то он так же будет преобразован в список, например, вот так список может быть получен из строки:
Помимо строк, аргументом может быть любой итератор, например range() :
В общем, любая последовательность не спискового типа данных, будет преобразована к списковому типу, что бывает очень полезно, для реализации многих алгоритмов обработки данных. Например, кортеж, который является неизменяемой версией списков, может быть преобразован в список вот так:
Словарь, который хранит данные в виде пар ключ — значение, так же может быть преобразован в список, но в результирующий список попадут только имена ключей:
Множества, которые хранят только уникальные объекты, так же могут быть преобразованы в списки:
Даже строки байтов могут быть преобразованы в список:
Ну а если функции list() передать список, то он будет возвращен как бы без изменений, но на самом деле будет возвращена его поверхностная копия:
Спискок — это последовательность
Выше было сказано, что если в качестве аргумента функции list() передать любую последовательность языка Python, то она будет преобразована в список. Последовательностями считаются любые типы данных, которые поддерживают:
- оператор извлечения срезов — [START:STOP:STEP] ;
- оператор вхождения in ;
- возможность определения длины (размера) с помощью функции len() ;
- возможность выполнять итерации по элементам;
Списки считаются последовательностями поскольку удовлетворяют всем вышеперечисленным требованиям. Функция len() возвращает длину (размер) списка:
Но будьте внимательны, len() не учитывает длину вложенных элементов, например, список [1, ‘abc’, [55, 66, 77]] состоит из трех элементов: числа, строки и списка.
Извлекать данные можно с помощью оператора [START:STOP:STEP] :
Проверить вхождение какого-нибудь элемента в список можно с помощью оператора in :
Кстати, если вам нужно, наоборот, убедиться в том, что какой-нибудь элемент не содержится внутри списка, то можно воспользоваться конструкцией not in :
Возможность выполнения итераций по элементам так же возможна благодаря конструкции for. in.
Любопытно, то что благодаря механизму распаковывания последовательностей возможно выполнение итераций по вложенным спискам одинаковой длины:
Список — это упорядоченная последовательность
Список является упорядоченной последовательностью в том смысле, что все его объекты упорядочены по своему местоположению, а доступ к ним выполняется с помощью целочисленных индексов, которые и определяют местоположение элементов.
Выше мы уже видели, что механизм индексации списков аналогичен индексации строк с помощью оператора [START:STOP:STEP] . Но из-за того, что список может содержать внутри себя абсолютно любые объекты, включая другие последовательности, то возникает необходимость в более сложных методах индексации:
Например, если необходимо получить доступ к символу ‘D’ , то его местоположение придется указывать с помощью трех операторов [] :
Несмотря на количество вложенных списков, получить доступ можно к абсолютно любому элементу, хотя с непривычки все-таки можно «заблудиться в трех соснах».
Списки — это изменяемые последовательности
Элементы списков и даже целые фрагменты списков могут быть изменены:
Чтобы изменить какой-нибудь элемент, достаточно обратиться к нему по индексу и указать его новое значение после оператора присваивания = :
Вставить элемент в определенную позицию можно следующим способом:
Заменить несколько элементов списка можно с помощью присваивания его срезу, списка аналогичной длины:
Если присвоить срезу списка пустой список, то это приведет к удалению элементов, которые входят в указанный срез:
Списки — это коллекции
Списки очень часто называют коллекциями, как раз потому что в отличие от массивов они могут содержать объекты разного типа и произвольные структуры данных (словари, множества и т.д.):
Обратите внимание, что в данном списке находятся числа, которые относятся к целым, вещественым и комплексным числовым типам данных, а также есть строка и еще один вложенный список. Массив же, в традиционном понимании этого слова, должен состоять только из элементов одинакового типа, например:
Пожалуй, единственное, где стоит относиться к спискам как к массивам, т.е. стараться что бы все элементы были одинакового типа — это научные вычисления и обработка данных с помощью таких пакетов как NumPy и Pandas. В этих случаях типизация массивов позволяет существенно ускорить работу алгоритмов. А во всех остальных случаях, списки — это самые настоящие коллекции, в которых можно хранить все что угодно, лишь бы это «что угодно» было объектом языка Python. Например, функции являются объектами языка Python, а значит они тоже могут храниться в списках, скажем вот так:
Более того, эти функции можно использовать, если вызвать их из списка с помощью оператора [] . Например, функция int() преобразует (если это возможно) любой объект в целое десятичное число:
А вот мы делаем тоже самое с помощью функции, которая хранится в списке F :
Вот так мы преобразуем число в строку:
А вот так мы можем сначала сделать из числа строку а потом из этой строки сделать список:
Вот таким образом может быть найдена сумма элементов списка:
А если хочется взглянуть на функции и методы, которые поддерживают списки, то можем выполнить F[4](F) .
Такие примеры могут только запутать, но данный пример показывает что любой объект языка Python может быть элементом в списке (и в любой другой коллекции), а значит он может быть использован и даже передан в другие списки.
8. Списки¶
Список (англ.: list) есть упорядоченный набор значений, где каждое значение доступно по индексу. Значения, входящие в список, называются элементами.
Списки похожи на строки, так как строки тоже являются упорядоченными наборами элементов — символов. Но в отличие от строк, элементы списка могут быть любых типов. Списки и строки, а также другие типы, являющиеся упорядоченными наборами, называются последовательностями.
8.2. Списочные значения¶
Есть несколько способов создать новый список, простейший из них — заключить элементы в квадратные скобки, [ и ] :
В первом примере у нас список из четырех целых чисел. Во втором — список из трех строк. Элементы списка не обязательно относятся к одному типу. Следующий список содержит строку, число с плавающей точкой, целое число и. еще один список:
Список внутри другого списка называют вложенным.
Наконец, список может вовсе не содержать элементов. Такой список называют пустым и обозначают [] .
В логическом выражении пустой список, так же, как 0 или пустая строка, считается ложью:
Мы можем присваивать списочные значения переменным и передавать списки в качестве аргументов при вызове функций:
8.3. Доступ к элементам¶
Для доступа к элементам списка используется тот же оператор [] , что и для доступа к символам строки. Выражение в квадратных скобках задает индекс. Не забывайте, что индексы начинаются с 0:
В качестве индекса можно использовать любое целочисленное выражение:
Если попытаться получить доступ к несуществующему элементу, то получим ошибку выполнения:
Если индекс отрицательный, то счет идет от конца списка:
Выражение numbers[-1] дает последний элемент списка, numbers[-2] — второй от конца, а элемента numbers[-3] не существует.
Часто в качестве индекса используется переменная цикла.
Этот цикл while считает от 0 до 4. Когда переменная цикла i становится равна 4, условие становится ложным и цикл завершается. Таким образом, тело цикла выполняется для i со значениями 0, 1, 2 и 3.
В каждой итерации переменная i используется как индекс для списка, чтобы вывести i -тый элемент. Этот прием называется обход списка.
8.4. Длина списка¶
Функция len возвращает длину списка, то есть, количество элементов в списке. В качестве верхней границы в цикле удобно использовать возвращаемое этой функцией значение, а не константу. При этом, если размер списка изменится, вам не придется просматривать программу и вносить изменения во все циклы, работающие с этим списком; они будут работать корректно со списком любого размера:
В последней итерации i равно len(horsemen) - 1 , то есть, индексу последнего элемента списка. Когда i становится равным len(horsemen) , условие цикла становится ложным и тело цикла не выполняется. И это правильно, поскольку len(horsemen) недопустимый для данного списка индекс.
Хотя список может содержать другой список, вложенный список считается одним элементом. Длина этого списка равна 4:
8.5. Проверка вхождения в список¶
Оператор in проверяет вхождение элемента в последовательность и дает в результате логическое значение. Мы уже использовали его со строками, но он также работает со списками и другими последовательностями:
Поскольку ‘pestilence’ входит в список horsemen , то оператор in возвращает True . Поскольку ‘debauchery’ не входит в список, in возвращает False .
Используя not вместе с in , можно проверить, что элемент не является элементом списка:
8.6. Операции над списками¶
Оператор + конкатенирует списки:
Оператор * повторяет элементы списка заданное число раз:
В первом примере 0 повторяется четыре раза. Во втором три раза повторяются элементы 1, 2, 3 .
8.7. Срезы списков¶
Мы выполняли срезы строк, но срезы также работают для списков:
8.8. Функция range ¶
В программировании часто требуются списки последовательных целых чисел, и Python предоставляет простой способ для их создания:
Функция range принимает два аргумента и возвращает список целых, начиная от числа, заданного первым аргументом, и до числа, заданного вторым аргументом, не включая последнее.
Можно вызывать range и по-другому. При вызове с единственным аргументом функция возвращает список, начинающийся с 0:
Третий аргумент, если он указан, задает шаг между соседними значениями в списке. Получим список чисел от 1 до 10 с шагом 2:
Если шаг задан отрицательным числом, то начальное число должно быть больше конечного:
Иначе результатом будет пустой список:
8.9. Списки изменяемы¶
В отличие от строк, списки изменяемы. Это означает, мы можем изменять их элементы. Используя оператор [] в левой части присваивания, можно избирательно обновить один из элементов:
Оператор [] может использоваться со списком в любом месте выражения. Если он появляется слева от оператора присваивания, он изменяет элемент списка. В приведенном примере первый элемент списка fruit изменяется с 'banana' на 'pear' , а последний — с 'quince' на 'orange' . Присваивание отдельному элементу не работает для строк:
Но работает для списков:
Используя срез, можно изменить несколько элементов сразу:
Можно также удалить элементы из списка, присвоив им пустой список:
А можно добавить элементы в список, втиснув их в пустой срез в нужном месте:
8.10. Удаление списка¶
Удаление элементов с помощью присваивания срезов довольно вычурно, и потому чревато ошибками. Python предлагает альтернативный способ, более легкий для чтения и понимания, и, к тому же, более универсальный.
del удаляет элемент из списка:
Как и следовало ожидать, del работает с отрицательными индексами, и генерирует ошибку выполнения, если заданный индекс выходит за границы разрешенного диапазона.
С del можно использовать срез:
8.11. Объекты и значения¶
Выполним предложения присваивания:
Теперь мы знаем, что и a и b указывают на строку "banana" . Но мы не можем сказать, указывают ли они на одну и ту же строку.
Есть два варианта:
В первом случае a и b указывают на два разных объекта с одинаковыми значениями. Во втором случае они ссылаются на один и тот же объект. Объект — это что-то, с чем может быть связано имя переменной.
У каждого объекта имеется уникальный идентификатор, который можно получить с помощью функции id . Отобразив идентификаторы объектов, на которые указывают a и b , мы узнаем, связаны ли эти переменные с одним и тем же объектом:
Мы два раза получили один и тот же идентификатор, а это значит, что Python создал только одну строку, и обе переменные, a и b , связаны с ней. Вы, вероятно, получите другое значение идентификатора.
Интересно, что списки ведут себя иначе. Если создать два списка, то мы получим два объекта:
На диаграмме это выглядит так:
Переменные a и b ссылаются на разные объекты, имеющие одинаковые значения.
8.12. Альтернативные имена¶
Поскольку переменные ссылаются на объекты, то, если мы присвоим одну переменную другой, обе переменные будут ссылаться на один и тот же объект:
На диаграмме это выглядит так:
Поскольку два разных имени, a и b , связаны с одним и тем же списком, будем называть их альтернативными именами. Изменения, сделанные с использованием одного имени, оказывают влияние и на другое:
Хотя такое поведение может быть полезным, иногда оно оказывается нежелательным. Вообще говоря, лучше избегать альтернативных имен, работая с изменяемыми объектами. А вот для неизменяемых объектов альтернативные имена не представляют никаких проблем. Поэтому Python создает альтернативные имена для строк, когда представляется случай сэкономить память компьютера.
8.13. Клонирование списков¶
Если нужно изменить список и при этом сохранить копию оригинального списка, то понадобится сделать копию самого списка, а не ссылки на него. Этот процесс иногда называют клонированием.
Простейший способ клонировать список — воспользоваться оператором среза:
Получение любого среза списка a приводит к созданию нового списка. В данном случае срез включает весь список.
Теперь можно изменять список b , не беспокоясь об a :
8.14. Списки и циклы for ¶
Цикл for также работает со списками. Синтаксис такой:
Это предложение эквивалентно следующему фрагменту кода:
Цикл for более лаконичен, поскольку мы можем обойтись без переменной цикла i . Вот рассмотренный выше цикл, переписанный с помощью for .
Он читается почти по-английски: для (каждого) horseman (англ.: всадник) в (списке) horsemen (англ.: всадники) напечатать horseman.
Любое списочное выражение может быть использовано в цикле for :
В первом примере выводятся все числа, кратные 3, между 0 и 19. Во втором примере выражается энтузиазм по поводу разных видов фруктов.
Поскольку списки изменяемы, часто выполняется обход списка с изменением каждого из его элементов. Следующий пример возводит в квадрат все числа в списке от 1 до 5 :
Подумайте над выражением range(len(numbers)) и разберитесь, как оно работает. В данном случае нам нужно как значение, так и индекс элемента списка для того, чтобы мы могли присвоить ему новое значение.
Такой прием довольно распространен в программировании, поэтому Python предлагает более красивый способ реализовать его:
Здесь функция enumerate в каждой итерации возвращает очередной индекс и связанное с ним значение. Еще один пример того, как работает enumerate :
8.15. Списочные параметры¶
При передаче списка в качестве аргумента передается ссылка на список, а не его копия. А поскольку списки изменяемы, то изменение параметра внутри функции означает также и изменение аргумента. Например, функция ниже принимает список в качестве аргумента и умножает каждый элемент списка на 2:
Если поместить функцию double_stuff в файл ch08.py , то сможем так протестировать ее:
Параметр a_list и переменная things являются альтернативными именами одного и того же объекта.
Если функция модифицирует списочный параметр, изменения будут видны в вызывающем коде.
8.16. Чистые и модифицирующие функции¶
Функции, которые принимают списки как аргументы и изменяют эти списки в ходе выполнения, называются модифицирующими, а изменения, которые они делают, называются побочным эффектом.
Чистая функция не производит побочных эффектов. Все ее связи с вызывающей программой сводятся к параметрам, которых она не изменяет, и возвращаемому значению. Вот чистая функция double_stuff :
Эта версия double_stuff не изменяет своих аргументов:
При использовании чистой функции double_stuff , для изменения things вам понадобится присвоить возвращаемое значение things :
8.17. Какая функция лучше?¶
Все, что можно сделать с помощью модифицирующих функций, может быть сделано и при помощи чистых функций. На самом деле, некоторые языки программирования поддерживают только чистые функции. Есть мнение, что программы, использующие только чистые функции, быстрее разрабатывать и в них закрадывается меньше ошибок. И все же, иногда модифицирующие функции удобны, а в отдельных случаях программы с чистыми функциями менее эффективны.
Вообще, мы рекомендуем писать чистые функции всегда, когда это разумно, и прибегать к модифицирующим только в случаях, когда их использование дает несомненное преимущество.
8.18. Вложенные списки¶
Вложенный список — это список, являющийся элементом другого списка. В следующем списке элемент с индексом 3 есть вложенный список:
Если ввести nested[3] , то получим [10, 20] . Извлечь элемент из вложенного списка можно за два шага:
А можно объединить эти два шага в выражение:
Оператор квадратная скобка вычисляется слева направо, так что это выражение берет 3-й элемент списка nested и извлекает из него 1-ый элемент.
8.19. Матрицы¶
Вложенные списки часто используют для того, чтобы представлять матрицы. Например, матрицу
можно представить так:
matrix есть список из трех элементов, в котором каждый элемент задает строку матрицы. Можно получить целую строку матрицы, как обычно:
Также можно извлечь отдельный элемент матрицы, используя два индекса:
Первый индекс выбирает строку, а второй — столбец. Хотя этот способ представления матриц самый распространенный, он не является единственным. Его вариацией является список столбцов вместо списка строк. Позднее мы увидим более радикальную альтернативу, использующую словарь.
8.20. Разработка через тестирование¶
Разработка через тестирование (англ.: Test-driven development, TDD) — это практика разработки программ, в которой программа создается серией небольших итераций, в каждой из которых сначала пишутся автоматические тесты, а затем код, реализующий тестируемую функциональность. От итерации к итерации растет реализованная и оттестированная функциональность.
Продемонстрируем разработку через тестирование с помощью доктестов. Скажем, нам нужна функция, которая создает матрицу с rows строк и columns столбцов, принимая аргументы для rows и columns .
Сначала подготовим тест для этой функции в файле matrices.py :
Выполнив скрипт, видим, что тест не прошел:
Тест не проходит, поскольку тело функции не содержит ничего, кроме строки в тройных кавычках, и поэтому возвращает None . Наш тест требует, чтобы функция возвращала матрицу 3 x 5, заполненную нулями.
Правила разработки через тестирование говорят, что для начала нужно написать самый простой вариант, который бы удовлетворял тест. Так что, в этом случае, просто вернем ожидаемый результат:
Теперь при выполнении скрипта тест успешно проходит, но наша реализация make_matrix всегда возвращает один и тот же результат, а это явно не то, что имелось в виду. В качестве мотивации дальнейших улучшений добавим тест:
Как и следовало ожидать, тест не проходит:
Этот процесс называется разработкой через тестирование, потому что код пишется только тогда, когда имеется тест, который не проходит. Мотивированные последним тестом, теперь напишем более общее решение:
Это решение, похоже, работает, поскольку тесты проходят. Однако, начав пользоваться новой функцией, быстро обнаружим баг:
Мы хотели присвоить значение 7 элементу во второй строке и третьем столбце, но, вместо этого, значение 7 получили все элементы третьего столбца!
По размышлении становится ясно, что в нашем текущем решении каждая строка матрицы — всего лишь ссылка на один и тот же список. Это определенно не то, что нам нужно. Приступая к исправлению бага, сначала напишем тест, демонстрирующий наличие этого бага:
Теперь, имея тест, который демонстрирует баг в программе, мы должны найти лучшее решение:
Процесс разработки через тестирование имеет ряд преимуществ. Этот процесс:
- заставляет конкретно думать о задаче, которую нужно решить, прежде чем пытаться ее решить,
- поощряет разбивать сложные задачи на более мелкие и простые, и пошагово приближаться к решению задачи в целом,
- дает набор автоматических тестов для программы, облегчая внесение в нее изменений и дополнений в дальнейшем.
8.21. Строки и списки¶
В Python есть функция list , которая принимает значение некоторой последовательности как аргумент и создает список из ее элементов.
Также существует функция str , которая берет любое значение Python как аргумент и возвращает его строковое представление.
Как видно из последнего примера, с помощью str не удается соединить вместе элементы списка символов. Это можно сделать с помощью функции join из модуля string :
Две очень полезные функции модуля string имеют дело со списками строк. Функция split разбивает строку на слова, возвращая список слов. По умолчанию считается, что слова отделяются друг от друга одним или более пробельными символами:
Необязательный аргумент позволяет указать, какие символы считать разделителями слов. В следующем примере в качестве разделителя указана последовательность двух символов ai :
Заметьте, что ai не попадает в список.
Функция string.join делает обратное функции string.split . Она принимает два аргумента: список строк и разделитель, который будет разделять элементы списка в результирующей строке.
8.22. Глоссарий¶
8.23. Упражнения¶
Напишите цикл, который обходит список
и выводит длину каждого элемента. Что происходит, когда вы передаете целое число функции len ? Замените 1 на 'one' и выполните вашу программу снова.
Создайте файл ch08e02.py следующего содержания:
Добавляйте следующие наборы доктестов в докстроку в начале файла и пишите код Python, который обеспечит прохождение доктестов. Добавляйте по одному набору доктестов за один раз.