Продолжаю разбираться с типами данных в Python и попутно — в Delphi 10.3, т.к. пока Python для меня — это «непознанный зверь», а в Delphi достаточно всяких проектов больших и малых которые хотя бы и для личного пользования, но надо поддерживать.
Итак, сегодня на повестке дня — списки (list) в Python. Список в Python — это упорядоченная последовательность элементов. А, как я говорил ранее, в Python всё — объекты. При этом списки относятся к изменяемым типам данных, то есть мы можем не только получить элемент списка по его индексу, но и изменить его. Но, обо всем по порядку.Итак, что же представляет собой список в Python, если рассматривать его с позиций Delphi? Список Python — это ни что иное, как обычный динамический массив. Например, в Delphi с некоторых пор мы можем задать массив и перечислить его элементы вот так:
var arr: array of integer; I: Integer; begin arr:=[4,5,6]; for I := Low(arr) to High(arr) do OutputDebugString(PChar(IntToStr(arr[i]))); end;
т.е. объявили динамический массив и присвоили ему три значения. В итоге индексы элементов у нас стали, соответственно, 0, 1 и 2. И теперь мы можем изменять элементы созданного массива, просто обращаясь к ним по индексу:
arr[1]:=6; arr[0]:=6;
Собственно, тоже самое можно делать и в Python со списками — создавать, обращаться к элементу по его индексу и изменять элементы:
>>> arr = [4,5,6] >>> arr [4, 5, 6] >>> arr[0] = 6 >>> arr[1] = 6 >>> arr [6, 6, 6]
Что же отличает список в Python от массива в Delphi?
1. Создание списков в Python
Если в Delphi мы обязаны объявить переменную, указать тип элементов массива и потом заполнить его элементами заданного типа, то в Python есть специальная функция — list(), которая преобразует любую последовательность в список. Например, вот такую нехитрую в Python операцию повторить без лишних телодвижений в Delphi не получится:
>>> arr2 = list("String") >>> arr2 ['S', 't', 'r', 'i', 'n', 'g']
Здесь все просто. Строка — это упорядоченная последовательность символов. Соответственно, передавая строку в функцию List(), на выходе мы получаем список где каждый его элемент — это отдельный символ строки.
Далее, в Python нам никто не запрещает объявлять список с разными типами элементов, перечислив их в квадратных скобках:
>>> arr4 = ['Строка', 1, 2, 3, '4'] >>> arr4 ['Строка', 1, 2, 3, '4']
С одной стороны кажется, что это нехорошо — давать записывать в список разные типы данных, но, с другой стороны — почему бы и нет? Я бы сказал, что это не нехорошо, а, скорее — непривычно после Delphi. Надо просто привыкнуть к таким особенностям языка.
Третий способ создания списка — заполнение поэлементно, например, вот так:
>>> arr5 = list() #Создали пустой список >>> arr5.append(1) #Добавили в список число >>> arr5.append('Строка');#Добавили в список строку >>> arr5 [1, 'Строка']
Как вы понимаете, в нынешней версии Delphi также есть подобная возможность при работе с динамическими массивами, правда, реализуется она несколько иначе:
var arr: array of integer; begin arr:=[1]; arr:=arr+[2]; arr:=arr+[3]; end;
2. Работа со списками в Python
2.1. Присвоение значений элементам списка
Выше я уже указал, что изменять элементы списка мы можем также, как и в Delphi — обратиться к элементу по индексу и присвоив необходимое значение. Однако, мы не можем добавить к списку новый элемент, указав в качестве индекса число, превышающее последний индекс:
>>> arr[3] = 5 Traceback (most recent call last): File "<pyshell#31>", line 1, in <module> arr[3] = 5 IndexError: list assignment index out of range
При работе с переменными типа list также следует иметь в виду, что в переменной сохраняется не сам объект, а ссылка на него. Эта особенность хорошо демонстрируется при групповом присваивании значений переменной (которого, кстати, нет в Delphi, но было бы неплохо иметь):
>>> x=y=[1,2] >>> x = y = [1,2] >>> x,y ([1, 2], [1, 2]) >>> x[0] = 100 >>> x,y ([100, 2], [100, 2])
Как видно из примера, в результате мы создали две переменные, которые ссылаются на один и тот же объект, а не два разных объекта. Кстати говоря, возвращаясь к теме работы со строками в Python, такая бы возможность (групповое присвоение значения переменным) при работе со строками сработала бы:
>>> s1 = s2 = "String" >>> s1=s1*3 >>> s1 'StringStringString' >>> s2 'String'
Правда изменить элемент строки по индексу мы бы не смогли, но об этом я я говорил здесь.
2.2. Создание копий списка
Итак, определились, что групповое присвоение значений не создает разные копии списков, соответственно, и такая запись не приведет к успеху, если нам необходимо создать копию:
>>> a = [1,2,3] >>> b = a >>> a is b True
Как идите, a и b — один и тот же объект.
В Delphi 10.3, кстати, то же самое:
var arr, arr2: array of integer; I: Integer; begin arr:=[1,2,3]; //создали массив на три элемента arr2:=arr; arr2[0]:=100; //перечисляем все элементы массива for I := Low(arr) to High(arr) do begin OutputDebugString(PChar('arr '+IntToStr(arr[i]))); OutputDebugString(PChar('arr2 '+IntToStr(arr2[i]))); end; end;
Здесь в итоге, оба первых элемента массивов в итоге будут равны 100.
Чтобы создать копию списка в Python можно:
1. Воспользоваться уже известной нам функцией list():
>>> a = [1,2,3] >>> b = list(a) >>> a, b ([1, 2, 3], [1, 2, 3]) >>> a is b False
2. Создать срез:
>>> a = [2,3,4] >>> b = a[:] >>> a is b False
Срез — очень полезная и интересная возможность Python для которой я сходу даже не могу припомнить аналогов в Delphi и про которую я планирую даже сделать отдельный пост.
3. Воспользоваться функцией copy():
>>> a = [5,6,7] >>> b = a.copy() >>> a,b ([5, 6, 7], [5, 6, 7]) >>> a is b False
Во всех трех случаях мы создали копии списков. Однако и здесь не обходится без «подводных камней». Как говорилось выше, список Python аналогичен динамическому массиву в Delphi. Соответственно, никто нам не запрещает делать вложенные списки, или, говоря в терминах Delphi — многомерные массивы. Например, можно создать вот такой список:
>>> a = [[1,2],[3,4]] >>> a [[1, 2], [3, 4]]
где каждый элемент списка — это ещё один список на два элемента. Теперь сделаем копию этого списка и попробуем в копии изменить какой-нибудь элемент вложенного списка, например, вот так:
>>> b = a.copy() >>> a is b False >>> b[0][0]=100 >>> a [[100, 2], [3, 4]] >>> b [[100, 2], [3, 4]]
Как видите «что-то пошло не так». Вроде бы и проверка показала, что переменные ссылаются на разные объекты, но изменение в списке b привело к изменению в списке a. Получается, что мы создали не полную копию списка, а копию «поверхности» (первого уровня, первого измерения — как угодно), а вот то, что было глубже — оставили ссылки на объекты. Чтобы создать полную копию списка необходимо воспользоваться функцией deepcopy() из модуля copy:
>>> a = [[1,2],[1,2]] >>> import copy >>> b = copy.deepcopy(a) >>> a is b False >>> b[0][0] = 100 >>> a,b ([[1, 2], [1, 2]], [[100, 2], [1, 2]])
Функция deepcopy() создает копию каждого объекта и, при этом, сохраняет внутреннюю структуру списка.
2.3. Различные функции работы со списками
1. len() — определение длины списка:
>>> x = [1,2,3] >>> len(x) 3
У объекта list определены следующие методы:
2. count(x) — подсчет количества элементов, равных x:
>>> x = [1,1,2,3,1,1] >>> x.count(1) 4
3. extend(x) — добавление в конец списка последовательности x:
>>> x = [1,1,2,3,1,1] >>> x.extend("Строка") >>> x [1, 1, 2, 3, 1, 1, 'С', 'т', 'р', 'о', 'к', 'а']
4. index(x) — поиск наименьшего индекса элемента, который равен x
Для демонстрации воспользуемся предыдущим примером:
>>> x [1, 1, 2, 3, 1, 1, 'С', 'т', 'р', 'о', 'к', 'а'] >>> x.index(1) 0 #самый первый элемент со значением 1 находится в самом начале списка >>> x.index("С") 6 #элемент со значением "С" находится на седьмой позиции и имеет индекс 6
5. insert(i, x) — вставка элемента x в i-ю позицию:
>>> z = [0,1,3] >>> z.insert(2,2) >>> z [0, 1, 2, 3]
6. pop(i) — возвращает i-й элемент, удаляя его из последовательности:
>>> z = [0,1,3] >>> z.insert(2,2) >>> z [0, 1, 2, 3] >>> y = z.pop(0) >>> y 0 >>> z [1, 2, 3]
7. reverse() — меняет порядок элементов на обратный:
>>> z [1, 2, 3] >>> z.reverse() >>> z [3, 2, 1]
8. sort() — сортирует элементы списка:
>>> z [3, 2, 1] >>> z.sort() >>> z [1, 2, 3]
Вот, пожалуй, на сегодня и всё. Что осталось «за бортом»:
1. перебор элементов списка различными способами
2. генераторы списков и выражения-генераторы
3. различные функции по работе с последовательностями.
Безусловно, по мере продолжения изучения возможностей Python я буду возвращаться к этим вопросам, однако, если вам не терпится рассмотреть эти вопросы прямо сейчас, то можете приобрести одну из книг по Python, которые представлены ниже.
Подведем небольшой итог. Итак, список (list) в Python представляет собой примерно тоже самое, что и динамический массив в Delphi. Вместе с этим, в Python возможности работы со списками несколько богаче в силу особенностей самого языка — можно задавать элементы списка различных типов, копировать списки буквально в одну строку кода, использовать срезу и т.д.
Книжная полка
![]() |
Описание Описан базовый синтаксис языка Python 3: типы данных, операторы, условия, циклы, регулярные выражения, встроенные функции, классы и объекты, итераторы и перечисления, обработка исключений, часто используемые модули стандартной библиотеки
|
Купить на ЛитРес |
![]() |
Автор: Майк МакГрат Название: Python. Программирование для начинающих Описание: Книга «Программирование на Python для начинающих» является исчерпывающим руководством для того, чтобы научиться программировать на языке Python. В этой книге с помощью примеров программ и иллюстраций, показывающих результаты работы кода, разбираются все ключевые аспекты языка. Установив свободно распространяемый интерпретатор Python, вы с первого же дня сможете создавать свои собственные исполняемые программы! |
Купить на ЛитРес |


