Список, кортеж и словарь – три основных структуры данных, которые позволяют работать с наборами данных. Список является аналогом массива в других языках, кортеж можно назвать неизменяемым массивом, а словарь похож на хеш-таблицу.
Список
Список в питоне можно создать перечислением значений через запятую в квадратных скобках:
Python 2.6.5 (r265:79063, Apr 1 2010, 05:28:39) [GCC 4.4.3 20100316 (prerelease)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> x = [4, 5, 2, "Hello!", 2.71878] >>> type(x) <type 'list'>
Ранее говорилось, что питон – язык с динамической типизацией. Так что и в списке мы можем хранить значения разных типов, в отличие от массивов в С (не говорите мне про void*). Можно, в том числе, хранить в списке и другие списки, что будет аналогом матрицы, кубического массива и т.п.
Получить элемент в массиве просто:
>>> x[0] 4 >>> x[3] 'Hello!'
Изменить тоже просто:
>>> x[0] = 123 >>> x[0] 123
Наверное, вам так и хочется вписать какой-нибудь большой индекс и посмотреть, что же выдаст питон. Нет, он не выдаст вам кусок памяти из соседнего массива:
>>> x[100500] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list index out of range
Найти дырку в питоне не удалось, он выдал нам ошибку, мол, индекс списка корявый. Про обработку исключительных ситуаций будет рассказано в одной из следующих статей.
А вот с отрицательными индексами это не произойдет:
>>> x[-1] 2.7187800000000002 >>> x[-2] 'Hello!'
Нет, это не баг. Это фича. Если индекс меньше нуля, то питон берет нужный вам элемент с конца списка. Правда, я вам немного соврал, когда говорил, что с отрицательными индексами питон не выдаст ошибку:
>>> x[-100500] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list index out of range
Но я думаю, вы и без меня бы догадались, что питон не выйдет за границы списка.
В отличие от кортежа, вы можете добавлять и удалять элементы из списка:
>>> my_list = [1, 2, 3, 4, 5, 6] >>> my_list.append(7) >>> my_list [1, 2, 3, 4, 5, 6, 7] >>> my_list.remove(3) >>> my_list [1, 2, 4, 5, 6, 7]
Есть также поиск (метод index), вставка в произвольное место (insert)… Подробности, как всегда, во встроенной справке, а здесь показательные выступления:
>>> my_list [1, 2, 4, 5, 6, 7] >>> my_list.append(2) >>> my_list.count(2) 2 >>> my_list.count(4) 1 >>> my_list.extend([-1, -2, -3]) >>> my_list [1, 2, 4, 5, 6, 7, 2, -1, -2, -3] >>> my_list.index(4) 2 >>> my_list.index(100500) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: list.index(x): x not in list >>> my_list.insert(0, 123) >>> my_list [123, 1, 2, 4, 5, 6, 7, 2, -1, -2, -3] >>> my_list.pop() -3 >>> my_list [123, 1, 2, 4, 5, 6, 7, 2, -1, -2] >>> my_list.remove(-1) >>> my_list [123, 1, 2, 4, 5, 6, 7, 2, -2] >>> my_list.reverse() >>> my_list [-2, 2, 7, 6, 5, 4, 2, 1, 123] >>> my_list.sort() >>> my_list [-2, 1, 2, 2, 4, 5, 6, 7, 123]
Срезы
Невероятно полезной возможностью питона является удобный синтаксис для срезов (slice). PHP’шники уже, наверное, догадались, о чем пойдет речь:
>>> x = [123, 5, 2, "Hello!", 2.71878] >>> x[1:4] [5, 2, 'Hello!']
Да, таким простым способом мы получили часть списка. Можно получить часть списка от начала до определенной точки:
>>> x[:3] [123, 5, 2]
Также можно получить часть списка от определенной точки до конца:
>>> x[3:] ['Hello!', 2.7187800000000002]
А вот получить список от начала до конца таким образом не удастся, но оно особо и не надо. Ну или если оно особо надо, то используйте конструктор копирования:
>>> x [123, 5, 2, 'Hello!', 2.7187800000000002] >>> y = x >>> z = list(x) >>> x[0] = 4 >>> x [4, 5, 2, 'Hello!', 2.7187800000000002] >>> y [4, 5, 2, 'Hello!', 2.7187800000000002] >>> z [123, 5, 2, 'Hello!', 2.7187800000000002]
Кстати, вы заметили, что список y не изменился? Потому что в строке y = x создается не копия объекта x, а ссылка на него, и помещается она в y. Такой механизм действует для всех объектов в питоне, кроме чисел, булевых переменных и None. Для строк тоже не действует. Прямо как в Java.
Знатоки функциональных языков уже должны были догадаться, что аналогом head является x[0], а аналогом tail – x[1:]. Ну ничего, позже я расскажу и о лямбда-функциях, и о свертках, а сейчас будут…
List comprehensions
Дословно это переводится как “список охвата”. Или “список включений”… В общем, я не встречал где-либо перевода для этого термина.
List comprehensions позволяют легко построить новый список на основе текущего. Аналог map и filter в функциональных языках (map с filter таки и тут есть, если интересно, то help(map) или help(filter)).
>>> numbers = range(1, 10) >>> numbers [1, 2, 3, 4, 5, 6, 7, 8, 9] >>> squares = [ x * x for x in numbers ] >>> squares [1, 4, 9, 16, 25, 36, 49, 64, 81]
Да, здесь мы сделали некое действие над всеми элементами списка и занесли результат в новый список.
Можно также отсеивать элементы в списке:
>>> evens = [ x for x in numbers if x % 2 == 0 ] >>> evens [2, 4, 6, 8]
Ну и разумеется эти действия можно совмещать:
>>> from math import sqrt >>> [ sqrt(i) for i in [-2, 4, -17, 9, 2] if i >= 0 ] [2.0, 3.0, 1.4142135623730951]
Кортежи
Или tuple. Википедия нам говорит, что это последовательность конечного числа элементов. И она не врет.
Вместо квадратных скобок используются обыкновенные.
>>> x = (1, 2, 3) >>> x (1, 2, 3) >>> x[0] 1 >>> x[0] = 123 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'tuple' object does not support item assignment >>> x.append(123) Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'tuple' object has no attribute 'append'
Обратите внимание, если вы хотите создать кортеж из одного элемента, то требуется поставить одну лишнюю запятую, иначе питон просто раскроет скобки:
>>> a = (False) >>> a False >>> type(a) <type 'bool'> >>> b = (True, ) >>> b (True,) >>> type(b) <type 'tuple'>
Из публичных методов объекта-кортежа есть только count и index, которые работают также, как в списке.
Кортеж можно разбить на составные части еще одним простым способом:
>>> foo, bar, lol = (5, 7, 9) >>> foo 5 >>> bar, lol (7, 9)
Это очень удобный способ задать значения сразу нескольким переменным. Можно даже без скобок:
>>> x1, x2 = -1, 1
Словари
Словарь – структура, которая хранит данные в форме “ключ: значение”. Аналог HashMap в Java. Используются фигурные скобки.
>>> d = {'first': True, 'second': False, 1: 123, 3.14: 456} >>> d {1: 123, 'second': False, 3.1400000000000001: 456, 'first': True} >>> type(d) <type 'dict'> >>> d[1] 123 >>> d["1"] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: '1' >>> d["second"] False
Напоминает JSON, правда?
Чтобы добавить элемент в словарь никакой append не нужен:
>>> d["hello"] = "world" >>> d {1: 123, 'second': False, 3.1400000000000001: 456, 'hello': 'world', 'first': True}
Можно легко получить список всех ключей, значений, или их кортежей:
>>> d.keys() [1, 'second', 3.1400000000000001, 'hello', 'first'] >>> d.values() [123, False, 456, 'world', True] >>> d.items() [(1, 123), ('second', False), (3.1400000000000001, 456), ('hello', 'world'), ('first', True)]
Есть также методы iterkeys, itervalues, iteritems, которые являются генераторами (как и упомянутый в прошлый раз xrange). А о генераторах речь пойдет нескоро.
Вот так просто можно пройти по словарю в цикле:
>>> en_ru = {'apple': 'яблоко', 'potato': 'картофель', 'tomato': 'томат', 'orange': 'апельсин'} >>> for english in en_ru.keys(): ... russian = en_ru[english] ... print english, russian ... tomato томат orange апельсин apple яблоко potato картофель
Или еще проще:
>>> for english, russian in en_ru.items(): ... print english, russian ... tomato томат orange апельсин apple яблоко potato картофель
Ну и еще одно показательное выступление:
>>> d {1: 123, 'second': False, 3.1400000000000001: 456, 'hello': 'world', 'first': True} >>> d.clear() >>> d {} >>> d = {'a': 'apple', 'b': 'bananna', 'c': 'cherry'} >>> d.copy() {'a': 'apple', 'c': 'cherry', 'b': 'bananna'} >>> d.has_key('a') True >>> d.has_key('z') False
Выводы
В ходе выполнения лабораторной работы мы изучили структу Такие структуры есть во многих языках программирования, но, возможно, в питоне ими удобнее пользоваться, чем в других. А возможно и нет. На вкус и цвет фломастеры разные.