Журнал LinuxFormat - перейти на главную

LXF76:Python

Материал из Linuxformat
Перейти к: навигация, поиск
Python
Python для профессионалов
Python + PyGame
Python + Web
Python + Clutter

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

Подробнее о типах данных

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

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

Задается список с помощью квадратных скобок, в которых элементы перечислены через запятую: [0, 1, 'два', 3.0, «четыре»]. Причем в отличие, скажем, от языка Pascal, вы вполне можете смешивать в одном списке данные разных типов. Индекс элемента, который вы хотите получить, задается также в квадратных скобках:

>>> a = [0, 1, 'two', 3.0]
>>> print a[1]
1

Как видите, первому элементу списка соответствует индекс 0. Специального синтаксиса для аналога многомерных массивов не предусмотрено, но вы вполне можете «конструировать» их с помощью вложенных списков, когда элементом списка является другой список:

>>> a = [[1,2,3],[4,5,6]]
>>> a[0]
[1, 2, 3]
>>> a[0][0]
1
>>> a[0][0] = 1234
>>> a
[[1234, 2, 3], [4, 5, 6]]

Для изменения списка существует ряд методов (почти все элементы в Python являются объектами классов, о чем мы поговорим в одном из следующих уроков; к терминологии же начнем привыкать уже сейчас). Например, append() позволяет добавлять новые элементы в конец списка:

>>> a = []
>>> a.append('q')
>>> a.append(123)
>>> a.append(a)
>>> print a
['q', 123, [...]]
>>> print a[2]
['q', 123, [...]]
>>> print a[2][2][2][2][0]
q

Интересно, не правда ли? Тут мы столкнулись со специальным типом данных — Ellipsis (отображается как троеточие). Он «зацикливает» последовательность саму на себя (обратите внимание, оператор print a[2] дал точно такой же результат, как и print a), в итоге получается своего рода бесконечная последовательность. Обычно используется при обработке многомерных матриц.

Рассмотрим еще несколько часто используемых методов:

>>> a = [1,2]
>>> a.insert(0,5)
>>> a
[5, 1, 2]
>>> a.remove(1)
>>> a
[5, 2]
>>> a.extend(a)
>>> a
[5, 2, 5, 2]
>>> a.pop()
2
>>> a
[5, 2, 5]

Разберемся, что делает этот код. Метод insert() вставляет элемент, значение которого задано во втором аргументе, начиная с позиции, заданной первым (в примере вставляем число 5 в начало списка). С помощью remove() вы можете удалить элемент по значению (если в списке несколько элементов с одним значением, удаляется первый из них). Метод extend() расширяет список заданной последовательностью (заметьте, как это отличается от append()), ну и pop() «выталкивает» из списка последний элемент. Удалить элемент по индексу можно оператором del, который справляется с любыми переменными: del a[1].

Помимо этого, вы можете использовать методы sort() и reverse(). Оставим их вам для самостоятельного изучения.

Для работы со списками в Python существует непревзойденный по гибкости механизм — так называемые срезы. Например, операция ar[2:5] возвратит список, содержащий элементы списка ar начиная с третьего (нумерация — с нуля!) и до шестого (исключительно). Пропуск того или иного индекса означает «с начала» или «до конца», отрицательный индекс — «с конца списка». А с помощью ar[1:8:2] будут выбраны только четные элементы (каждый второй) из диапазона 1-7. Внимательно рассмотрите приведенные ниже примеры, поэкспериментируйте сами, и вам все станет понятно:

>>> a = [0,1,2,3,4,5,6,7,8,9]
>>> a[3:5]
[3, 4]
>>> a[4:], a[:2]
([4, 5, 6, 7, 8, 9], [0, 1])
>>> a[-2:]
[8, 9]
>>> a[:]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a[1:9:3]
[1, 4, 7]
>>> a[::2]
[0, 2, 4, 6, 8]

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

>>> a = [b**2 for b in [1,2,3,4,5] if b > 2]
>>> print a
[9, 16, 25]

Оператор «**» — это возведение в степень. Секция if спискового включения может быть опущена (в ней задается фильтрующее условие). Вместо явного указания списка (после in) вы, естественно, можете использовать и переменную, содержащую последовательность. Поэкспериментируйте со списковыми включениями — с их помощью можно достигать удивительных результатов.

Кортеж — это неизменяемый список. Элементы в нем упорядочены по индексам, обращаться вы можете к ним так же, как и в списке, но методы, изменяющие кортеж, отсутствуют. Содержимое кортежа записывается в круглых скобках — tuple = (1, 2, «three»). Если вам нужно задать кортеж из одного элемента, поставьте после него запятую — ('5',).

Замечу, что операции среза применимы и к кортежам (поскольку сам кортеж при этом не изменяется, а просто создается новая переменная, тоже кортеж, на его основе).

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

Вы можете складывать списки со списками или кортежи с кортежами — результат будет содержать элементы последовательностей-"слагаемых", причем обратите внимание, что порядок элементов всегда строго сохраняется:

>>> b = [3,4,5]
>>> c = [1,2]
>>> d = b + c + [9,8,7]
>>> print d
[3, 4, 5, 1, 2, 9, 8, 7]
>>> d = [9,8,7] + c + b
>>> print d
[9, 8, 7, 1, 2, 3, 4, 5]
>>> (1,2) + (3,4)
(1, 2, 3, 4)

Теперь самое время познакомиться с циклом for. Он позволяет проходить по каждому элементу последовательности, выполняя те или иные действия:

>>> a = [1,2,3,4,5]
>>> for i in a:
...     print i * 2,
...
2 4 6 8 10

Про отступы, думаю, вы помните. Запятая после операнда в операторе print отменяет перевод строки, благодаря чему выводимые значения располагаются на одной строке. Для организации привычного многим цикла «от X до Y» используется функция range(X, Y), генерирующая нужную последовательность:

>>> for i in range(3, 8):
...     print i,
...
3 4 5 6 7

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

Еще один тип последовательности — строка. При некотором допущении она может рассматриваться как кортеж символов (в том плане, что не позволяет выполнять изменение отдельных элементов «на месте»). Строка допускает операции среза, ее можно использовать в цикле for для прохода по каждой букве, и так далее.

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

>>> dict = {
... 'ru': 'Russia',
... 'uk': 'United Kingdom',
... }
>>> print dict
{'ru': 'Russia', 'uk': 'United Kingdom'}
>>> dict.pop('uk')
'United Kingdom'
>>> print dict
{'ru': 'Russia'}
>>> dict['us'] = 'USA'
>>> print dict
{'ru': 'Russia', 'us': 'USA'}
>>> print dict['ru']
Russia
>>> dict.keys()
['ru', 'us']
>>> dict.values()
['Russia', 'USA']
>>> dict.items()
[('ru', 'Russia'), ('us', 'USA')]

Запись присвоения переменной dict выполнена на нескольких строках для удобства представления (внутри фигурных скобок вы можете переносить строки и устанавливать любые отступы; аналогично можно поступать и со списками и кортежами). Но вы вполне можете записывать все в одной строке. Обращение к элементу словаря по ключу выполняется так же, как вы выбор элемента списка по индексу (с той разницей, что ключ не обязан быть целым числом). Если присвоить значение несуществующему элементу, то он добавится в словарь. Последние три метода, показанные в примере, позволяют получить соответствующие списки (ключей, значений и кортежей «ключ-значение»), которые могут быть использованы, например, для обработки словаря в цикле:

>>> arkeys = dict.keys()
>>> arkeys.sort()
>>> for domain in arkeys:
...     print "%s = %s" % (domain, dict[domain])
...
ru = Russia
us = USA

Кстати, переменные, значением которых заполняются знакоместа %s при выводе текста, если таковых две и больше, должны передаваться как кортеж, то есть в круглых скобках. Может использоваться и особый «словарный» синтаксис, использование которого будет продемонстрировано в одном из дальнейших примеров.

Функции и модули

Чтобы завершить разговор о типах данных, нужно несколько слов сказать о функциях и модулях. Функция позволяет использовать один и тот же фрагмент кода в разных частях программы. Различают встроенные функции (которые «зашиты» в интерпретатор) и пользовательские. О вторых речь пойдет в следующем уроке, а сейчас коротко остановимся на встроенных.

В первой статье цикла мы уже встречались с функцией float(), которая преобразует целое число или строку, переданные ей в качестве аргумента, в число с плавающей запятой. Как вы видели, вызов функции происходит по имени, а в скобках передаются аргументы, над которыми функция выполняет действия. Функция может не иметь аргументов, однако указывать скобки после ее имени необходимо. Результат своей работы функция возвращает основной программе (причем вызов функции трактуется в выражениях именно как это возвращаемое значение; например, в выражении sum = z + float(b) к переменной z добавится результат, возвращенный функцией, а не сама функция). Функция может и не возвращать значения явно — в этом случае возвращается результат специального типа None.

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

>>> import types
>>> for t in [t for t in dir(types) if t[0:2] != '__']:
...     print t

Первой строкой мы подключаем один из системных модулей - types. Модуль — это программа на Python, содержащая функции, переменные, классы и т. д., которые вы можете в дальнейшем использовать в своих сценариях. Подробнее о них разговор у нас пойдет в следующий раз. Пока достаточно знать, что здесь мы подгружаем модуль types и получаем доступ к его функциям, служащим для преобразования типов. Их полный список выводит функция dir(), ну а про списковые включения вы уже знаете. Поясню только фрагмент if — с его помощью мы исключаем из вывода специальные функции и переменные, которые начинаются двумя символами подчеркивания (здесь мы применяем операцию среза к строке t).

В результате выполнения этого кода вы получите список из 35 функций преобразования, соответствующих типам Python. Можно увидеть, что и функции, и классы являются допустимыми типами данных, что позволяет присваивать их переменным: например, вы можете записать mydirfunc = dir, и в дальнейшем mydirfunc можно будет использовать точно так же, как и функцию dir: print mydirfunc(types).

Типов данных существует достаточно много, но для начала работы с Python достаточно тех, что были описаны выше.

Подведем итог. Сегодня мы не написали ничего полезного, но заложили фундамент для дальнейшей работы.

Персональные инструменты
купить
подписаться
Яндекс.Метрика