Список, кортеж и словарь — три основных структуры данных, которые позволяют работать с наборами данных. Список является аналогом массива в других языках, кортеж можно назвать неизменяемым массивом, а словарь похож на хеш-таблицу.
Список в питоне можно создать перечислением значений через запятую в квадратных скобках:
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 позволяют легко построить новый список на основе текущего. Аналог 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
В ходе выполнения лабораторной работы мы изучили структу Такие структуры есть во многих языках программирования, но, возможно, в питоне ими удобнее пользоваться, чем в других. А возможно и нет. На вкус и цвет фломастеры разные.