list - це змінна колекція елементів у послідовності.
Як і більшість колекцій (дивіться вбудовані tuple, dict і set), масиви можуть зберігати посилання на будь-який тип (або кілька типів) даних, зокрема на інші масиви.
У Python їх вважають послідовністю, і їх можна копіювати повністю або частково за допомогою синтаксису зрізів.
Як і в будь-якій послідовності, до елементів усередині lists можна звертатися за номером 0-based index зліва або за номером -1-based index справа.
Масиви підтримують як загальні, так і змінні операції над послідовностями, як-от min(<list>)/max(<list>), <list>.index(), <list>.append() і <list>.reverse().
Елементи можна перебирати за допомогою конструкції for item in <list>, а також for index, item in enumerate(<list>), коли потрібні і сам елемент, і його індекс.
Python надає багато корисних методів для роботи з масивами.
Оскільки масиви змінні, методи масиву змінюють вихідний обʼєкт масиву, переданий у метод.
Якщо змінювати обʼєкт небажано, потрібно зробити shallow copy (щонайменше) вихідного list за допомогою slice або <list>.copy().
Додати елементи в кінець наявного масиву можна за допомогою <list>.append(<item>):
>>> numbers = [1, 2, 3]
>>> numbers.append(9)
>>> numbers
[1, 2, 3, 9]
Замість додавання в кінець, <list>.insert(<index>, <item>) додає елемент за конкретним індексом усередині масиву.
<index> - це індекс елемента, перед яким має зʼявитися новий елемент.
<item> - це елемент, який потрібно вставити.
Примітка: Якщо <index> дорівнює 0, елемент буде додано на початок масиву.
Якщо <index> більший за останній індекс у масиві, елемент буде додано в останню позицію, що рівнозначно використанню <list>.append(<item>).
>>> numbers = [1, 2, 3]
>>> numbers.insert(0, -2)
>>> numbers
[-2, 1, 2, 3]
>>> numbers.insert(1, 0)
>>> numbers
[-2, 0, 1, 2, 3]
iterable можна поєднати з наявним масивом (тобто зʼєднати їх) за допомогою <list>.extend(<iterable>).
<list>.extend(<iterable>) розпакує переданий iterable, додаючи його елементи в тому самому порядку в кінець цільового масиву.
Якби тут використати <list>.append(<item>), увесь iterable додався б як один елемент.
>>> numbers = [1, 2, 3]
>>> other_numbers = [5, 6, 7]
>>> numbers.extend(other_numbers)
>>> numbers
[1, 2, 3, 5, 6, 7]
>>> numbers.extend([8, 9])
>>> numbers
[1, 2, 3, 5, 6, 7, 8, 9]
<list>.remove(<item>) можна використати, щоб видалити елемент із масиву.
<list>.remove(<item>) викине ValueError, якщо такого елемента в масиві немає.
>>> numbers = [1, 2, 3]
>>> numbers.remove(2)
>>> numbers
[1, 3]
# Trying to remove a value that is not in the list throws a ValueError.
>>> numbers.remove(0)
ValueError: list.remove(x): x not in list
Або ж метод <list>.pop(<index>) і видалить елемент, і поверне його (return) для подальшого використання.
<list>.pop(<index>) приймає один необовʼязковий параметр: index елемента, який треба видалити й повернути.
Якщо необовʼязковий аргумент <index> не вказано, буде видалено й повернено останній елемент масиву.
Якщо <index> більший за останній індекс масиву, буде викинуто IndexError.
>>> numbers = [1, 2, 3]
>>> numbers.pop(0)
1
>>> numbers
[2, 3]
>>> numbers.pop()
3
>>> numbers
[2]
# This will throw an error because there is only index 0.
>>> numbers.pop(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: pop index out of range
Усі елементи можна видалити з list за допомогою <list>.clear(). Він не приймає жодних параметрів.
>>> numbers = [1, 2, 3]
>>> numbers.clear()
>>> numbers
[]
Порядок елементів масиву можна обернути на місці за допомогою <list>.reverse(). Це змінить вихідний масив.
>>> numbers = [1, 2, 3]
>>> numbers.reverse()
>>> numbers
[3, 2, 1]
Масив можна перевпорядкувати на місці за допомогою <list>.sort().
Типовий порядок сортування - за зростанням зліва.
Документація Python пропонує додаткові поради й прийоми сортування.
З 2002 по 2022 рік Python внутрішньо використовував для впорядкування масивів алгоритм під назвою Timsort, але з Python 3.11 перейшов на Powersort.
Докладніше про цю зміну та її обговорення командою розробників ядра Python можна прочитати в GitHub issue 78742.
Технічні подробиці алгоритму наведено в статті J. Ian Munro та Sebastian Wild Nearly-Optimal Mergesorts: Fast, Practical Sorting Methods That Optimally Adapt to Existing Runs
>>> names = ["Tony", "Natasha", "Thor", "Bruce"]
# The default sort order is *ascending*.
>>> names.sort()
>>> names
["Bruce", "Natasha", "Thor", "Tony"]
Щоб відсортувати масив у спадному порядку, передаймо методу аргумент reverse=True:
>>> names = ["Tony", "Natasha", "Thor", "Bruce"]
>>> names.sort(reverse=True)
>>> names
["Tony", "Thor", "Natasha", "Bruce"]
Коли змінювати вихідний list небажано, можна скористатися вбудованими функціями sorted() і reversed().
sorted(<list>) поверне відсортовану копію й приймає ті самі параметри, що й <list>.sort().
reversed(<list>) повертає ітератор, який видає елементи масиву у зворотному порядку.
Iterators докладно розглянемо в іншій вправі.
Дізнатися, скільки разів елемент трапляється в масиві, можна за допомогою <list>.count(<item>).
Він повертає загальну кількість разів, які <item> трапляється в масиві як елемент.
>>> items = [1, 4, 7, 8, 2, 9, 2, 1, 1, 0, 4, 3]
>>> items.count(1)
3
<list>.index(<item>) поверне номер індексу першого входження переданого елемента.
Якщо входжень немає, виникає ValueError.
Індексація 0-based ведеться зліва, тобто позиція першого елемента - це індекс 0.
Також підтримується індексація справа, яка починається з індексу -1.
>>> items = [7, 4, 1, 0, 2, 5]
>>> items.index(4)
1
>>> items.index(10)
ValueError: 10 is not in list
Якщо вказати індекси start і end, пошук відбудеться в межах конкретної ділянки масиву:
>>> names = ["Tina", "Leo", "Thomas", "Tina", "Emily", "Justin"]
>>> names.index("Tina")
0
>>> names.index("Tina", 2, 5)
3
Якщо точна позиція елемента не потрібна, вбудований оператор in ефективніше перевіряє належність.
>>> names = ["Tina", "Leo", "Thomas", "Tina", "Emily", "Justin"]
>>> "Thomas" in names
True
Памʼятаймо, що змінні в Python - це імена, які вказують на обʼєкти, що стоять за ними.
Упродовж роботи програми імена можна привʼязувати й перепривʼязувати до різних обʼєктів.
Присвоєння обʼєкта list новій змінній не копіює ні сам обʼєкт, ні жодних даних, на які він посилається.
І нове, і старе імʼя вказуватимуть на той самий обʼєкт list.
Крім того, масиви - це обʼєкти контейнерного типу. Щоб заощадити місце, контейнери зберігають лише посилання на елементи, а не самі елементи.
Ця «оптимізація» може мати непередбачувані наслідки для неуважних.
<list>.copy() створить новий обʼєкт list, але не створить нових обʼєктів для елементів масиву, на які він посилається: копія буде «поверхневою».
shallow copy зазвичай достатньо, коли треба додати або видалити елементи в одному з обʼєктів list, не змінюючи інший.
Але якщо є хоч найменший шанс, що елементи, на які посилається list, випадково зміняться (а отже, зміняться й усі повʼязані поверхневі копії), варто скористатися copy.deepcopy() із модуля copy, щоб створити повну, або «глибоку», копію всіх посилань і обʼєктів.
Докладне пояснення поведінки імен, значень, масивів і вкладених масивів можна знайти в цьому чудовому дописі в блозі від Ned Batchelder: Names and values: making a game board. Shallow vs Deep Copying of Python Objects також дає гарний огляд того, що варто враховувати під час копіювання.