Python: структуры данных

Автор: | 06/30/2017
 

PythonПеревод — краткий обзор структур данных в Python.

Оригинал — тут>>>.

В Python 3 имеется четыре встроенных типа данных — списки (list), кортежи (turple), словари (dictionary) и списки (set).

Списки (list)

Список (list) в Python представляет собой упорядоченную коллекцию элементов, т.е. вы храните последовательность элементов в списке. Вы можете представлять их как списсок покупок в магазине, но с той разницей, что в вашем списке покупок каждый элемент скорее всего будет в новой строке, а в Python — они разделяются запятыми.

Такой список элементов должен быть заключён в квадратные скобки. После того, как вы создали список — вы можете добавлять, удалять и выполнять поиск по элементам в нём.

Т.к. мы можем добавлять и удалять данные в списках — то они называются изменяемыми (mutable) типов данных.

Краткий обзор объектов и классов

Списки являются отличными примером использования объектов и классов. Когда мы используем переменную i и присваиваем ей значение, например целочисленное 5 — вы можете представлять себе это как создание объекта/интанса с именем i класса integer.

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

Например — Python предоставляет метод append класса list, который позволяет добавить элемент в список. Так, mylist.append('item') добавит строку «item» к списку mylist.

Кроме того — класс может так же иметь поля/атрибуты, которые являются ничем иным, как переменными этого класса.

Пример списков в Python

Возьмём следующий скрипт:

#!/usr/bin/env python

shoplist = ['apple', 'mango', 'carrot', 'banana']

print('I have', len(shoplist), 'items to purchase.')

print('These items are:', end=' ')
for item in shoplist:
    print(item, end=' ')

print('\nI also have to buy rice.')
shoplist.append('rice')
print('My shopping list is now', shoplist)

print('I will sort my list now')
shoplist.sort()
print('Sorted shopping list is', shoplist)

print('The first item I will buy is', shoplist[0])
olditem = shoplist[0]
del shoplist[0]
print('I bought the', olditem)
print('My shopping list is now', shoplist)

Результат его выполнения:

./ds_using_list.py
I have 4 items to purchase.
These items are: apple mango carrot banana
I also have to buy rice.
My shopping list is now [‘apple’, ‘mango’, ‘carrot’, ‘banana’, ‘rice’]
I will sort my list now
Sorted shopping list is [‘apple’, ‘banana’, ‘carrot’, ‘mango’, ‘rice’]
The first item I will buy is apple
I bought the apple
My shopping list is now [‘banana’, ‘carrot’, ‘mango’, ‘rice’]

Как это работает

Переменная shoplist представляет собой «список покупок». В ней мы храним строки — названия того, что требуется купить, но вы можете добавить в список любой тип объекта, включая числа и даже другие списки (вложенные списки):

>>> shoplist = ['apple', 'mango', 'carrot', 'banana']
>>> otherlist = ['item1', 'item2']
>>> shoplist.append(otherlist)
>>> print(shoplist)
['apple', 'mango', 'carrot', 'banana', ['item1', 'item2']]

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

>>> for i in shoplist:
...   print(i)
... 
apple
mango
carrot
banana
['item1', 'item2']

Кроме метода append() выше — мы можем использовать оператор del, что бы удалить элемент списка.

Например — удалить последний элемент (вложенный список otherlist, добавленный с помощью append() в конец списка):

>>> del shoplist[-1]
>>> for i in shoplist:
...   print(i)
... 
apple
banana
carrot
mango

Мы так же использовали метод sort для сортировки элементов списка:

>>> shoplist.sort()
>>> for i in shoplist:
...   print(i)
... 
apple
banana
carrot
mango

Кортежи (tuple)

Кортежи используются для  хранения нескольких объектов. По сути кортежи схожи со списками, с той разницей что они не предоставляют такой функциональности, как списки. Главное их отличие — кортежи явлются неизменямым (immutable) типом данных.

Кортежи задаются через запятую и опционально — с добавлением круглых скобочек:

>>> tuple = 'item1', 'item2'
>>> type(tuple)
<class 'tuple'>
>>> tuple = ('item1', 'item2')
>>> type(tuple)
<class 'tuple'>

Пример кортежей в Python

Рассмотрим такой скрипт:

#!/usr/bin/env python

# I would recommend always using parentheses
# to indicate start and end of tuple
# even though parentheses are optional.
# Explicit is better than implicit.
zoo = ('python', 'elephant', 'penguin')
print('Number of animals in the zoo is', len(zoo))

new_zoo = 'monkey', 'camel', zoo
print('Number of cages in the new zoo is', len(new_zoo))
print('All animals in new zoo are', new_zoo)
print('Animals brought from old zoo are', new_zoo[2])
print('Last animal brought from old zoo is', new_zoo[2][2])
print('Number of animals in the new zoo is',
      len(new_zoo)-1+len(new_zoo[2]))

Результат его выполнения:

./ds_using_tuple.py
Number of animals in the zoo is 3
Number of cages in the new zoo is 3
All animals in new zoo are (‘monkey’, ‘camel’, (‘python’, ‘elephant’, ‘penguin’))
Animals brought from old zoo are (‘python’, ‘elephant’, ‘penguin’)
Last animal brought from old zoo is penguin
Number of animals in the new zoo is 5

Как это работает

Переменная zoo является кортежем элементов.

Мы можем использовать метод len() для получения длины кортежа, что свидельствуюет о том, что как и списки — кортежи являются последовательностями (см. ниже).

>>> zoo = ('python', 'elephant', 'penguin')
>>> len(zoo)
3

По аналогии со списками — мы можем так же использовать вложенные кортежи:

>>> newnew_zoo = 'monkey', 'camel', zoo
>>> print(newnew_zoo)
('monkey', 'camel', ('python', 'elephant', 'penguin'))

Как и со списками — мы можем использовать срезы (slice) для доступа к элементам кортежа. При этом помните, что нумерация элементов начинается с 0:

>>> print(newnew_zoo[0])
monkey
>>> print(newnew_zoo[-1])
('python', 'elephant', 'penguin')
>>> print(newnew_zoo[-1][0])
python

Словари (dictionary)

Словарь представлояет собой что-то вроде «записной книги» — адрес человека зная только его имя: в словаре ключ (key) ассоциируется со значением (value).

Поните, что все ключи в одном словаре должны быть уникальными.

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

Пара ключ:значение в словаре указываются с помощью нотации dict = {key1:value1, key2: valu2}.

Все ключи в словаре хранятся в неупорядоченном состоянии.

Словари являются объекатами класса dict.

Пример словаря в Python

Рассмотрим такой скрипт:

#!/usr/bin/env python

# 'ab' is short for 'a'ddress'b'ook

ab = {
    'Swaroop': 'swaroop@swaroopch.com',
    'Larry': 'larry@wall.org',
    'Matsumoto': 'matz@ruby-lang.org',
    'Spammer': 'spammer@hotmail.com'
}

print("Swaroop's address is", ab['Swaroop'])

# Deleting a key-value pair
del ab['Spammer']

print('\nThere are {} contacts in the address-book\n'.format(len(ab)))

for name, address in ab.items():
    print('Contact {} at {}'.format(name, address))

# Adding a key-value pair
ab['Guido'] = 'guido@python.org'

if 'Guido' in ab:
    print("\nGuido's address is", ab['Guido'])

Результат его выполнения:

./ds_using_dict.py
Swaroop’s address is swaroop@swaroopch.com
There are 3 contacts in the address-book
Contact Swaroop at swaroop@swaroopch.com
Contact Larry at larry@wall.org
Contact Matsumoto at matz@ruby-lang.org
Guido’s address is guido@python.org

Как это работает

Мы создали словарь ab, после чего получаем доступ к значением по ключам:

>>> ab = {
...     'Swaroop': 'swaroop@swaroopch.com',
...     'Larry': 'larry@wall.org',
...     'Matsumoto': 'matz@ruby-lang.org',
...     'Spammer': 'spammer@hotmail.com'
... }
>>> print(ab['Swaroop'])
swaroop@swaroopch.com

Используя уже знакомый оператор del — мы можем удалять пару ключ-значение, при этом достаточно знать только ключ:

>>> del ab['Swaroop']
>>> print(ab['Swaroop'])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'Swaroop'
>>> print(ab)
{'Larry': 'larry@wall.org', 'Matsumoto': 'matz@ruby-lang.org', 'Spammer': 'spammer@hotmail.com'}

Далее — мы используем метод items(), который возвращает нам список кортежей, где каждый кортеж хранит пару ключ:значение:

>>> print(ab.items())
dict_items([('Larry', 'larry@wall.org'), ('Matsumoto', 'matz@ruby-lang.org'), ('Spammer', 'spammer@hotmail.com')])

Более того — мы можем использовать цикл for..in, присваивая ключ в переменную name а значение — в address:

>>> for name, address in ab.items():
...   print(name, address)
... 
Larry larry@wall.org
Matsumoto matz@ruby-lang.org
Spammer spammer@hotmail.com

И так же мы может добfвить новую пару ключ:значение в словарь:

>>> print(ab['Guido'])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'Guido'
>>> ab['Guido'] = 'guido@python.org'
>>> print(ab['Guido'])
guido@python.org

И проверять наличие ключа, используя оператор in:

>>> if 'Guido' in ab:
...   print(ab['Guido'])
... 
guido@python.org

Последовательности (sequence)

Списки, кортежи и строки являются примерами последовательностей, но что такое последовательность?

Главной отличительной возможностью последовательностей является проверка членства (membership test), т.е. применение выражений in и not in, а так же использование операций индексирования (indexing operations), которые позволяют получать определённые элементы из последовательности.

Три типа последовательностей, упомянутых выше — списки, кортежи и строки, так же имеют возможность применения слайсинга (slicing), которая позволяет получить часть последовательности.

Пример последовательностей в Python

Рассмотрим такой скрипт:

#!/usr/bin/env python

shoplist = ['apple', 'mango', 'carrot', 'banana']
name = 'swaroop'

# Indexing or 'Subscription' operation #
print('Item 0 is', shoplist[0])
print('Item 1 is', shoplist[1])
print('Item 2 is', shoplist[2])
print('Item 3 is', shoplist[3])
print('Item -1 is', shoplist[-1])
print('Item -2 is', shoplist[-2])
print('Character 0 is', name[0])

# Slicing on a list #
print('Item 1 to 3 is', shoplist[1:3])
print('Item 2 to end is', shoplist[2:])
print('Item 1 to -1 is', shoplist[1:-1])
print('Item start to end is', shoplist[:])

# Slicing on a string #
print('characters 1 to 3 is', name[1:3])
print('characters 2 to end is', name[2:])
print('characters 1 to -1 is', name[1:-1])
print('characters start to end is', name[:])

Результат его выполнения:

./ds_seq.py
Item 0 is apple
Item 1 is mango
Item 2 is carrot
Item 3 is banana
Item -1 is banana
Item -2 is carrot
Character 0 is s
Item 1 to 3 is [‘mango’, ‘carrot’]
Item 2 to end is [‘carrot’, ‘banana’]
Item 1 to -1 is [‘mango’, ‘carrot’]
Item start to end is [‘apple’, ‘mango’, ‘carrot’, ‘banana’]
characters 1 to 3 is wa
characters 2 to end is aroop
characters 1 to -1 is waroo
characters start to end is swaroop

Как это работает

Индексирование

Сначала мы применяем индексы для получения элемента последовательности:

>>> shoplist = ['apple', 'mango', 'carrot', 'banana']
>>> print(shoplist[0])
apple

При этом помните, что индексы в Python начинаются с нуля, т.е. для получения первого элемента — используется индекс 0 ([0]), а для получения, например, четвёртого элемента — используется индекс 3 ([3]).

Кроме того — вы можете использовать отрицательные индексы — в таком сулчае отсчёт будет выполнен от конца последательности, т.е. [-1] вернёт последний элемент, [-2] — предпоследний и т.д.:

>>> print(shoplist[-1])
banana
Слайсинг

Операция слайсингасреза«) выполняется с указанием имени последовательности и опционально — пары чисел (индексов), разделённых двоеточием:

>>> print(shoplist[1:3])
['mango', 'carrot']

Вы можете пропустить первое или последнее значение. В таком случае Python выведет элементы от первого до заданного индекса, или наоборот:

>>> print(shoplist[:3])
['apple', 'mango', 'carrot']
>>> print(shoplist[3:])
['banana']

Либо не указывать их вообще:

>>> print(shoplist[:])
['apple', 'mango', 'carrot', 'banana']
>>> print(shoplist)
['apple', 'mango', 'carrot', 'banana']

Как и с индексами — вы можете использовать отрицательные значения для получения среза:

>>> print(shoplist[:-1])
['apple', 'mango', 'carrot']
>>> print(shoplist[-1:-1])
[]
>>> print(shoplist[-1:])
['banana']

Более того — допустимо указание третьего аргумента, который задаёт шаг среза (по умолчанию равен единице):

>>> print(shoplist[::2])
['apple', 'carrot']

Множества (set) 

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

Используя множества — вы можете использовать проверки членства, добавлять и удалять элементы, объединять их, выполнять проверку на принадлежность другому множеству и так далее. Элементом множества может являтся любой неизменяемый тип данных — числа, строки, кортежи.

Например:

>>> bri = set(['brazil', 'russia', 'india'])
>>> 'india' in bri
True
>>> 'usa' in bri
False
>>> bric = bri.copy()
>>> bric.add('china')
>>> bric.issuperset(bri)
True
>>> bri.remove('russia')
>>> bri & bric
{'india', 'brazil'}

В оригинальной статье так же описываются ссылки (refences) и некоторые детали строк (strings).