Главная страница
Навигация по странице:

  • M = [[1, 2, 3]

  • Дополнительные операции над списками

  • [row[1] + 1 for row in M]

  • D = {food: Spam, quantity: 4, color: pink}

  • D[food]

  • D = {} >>> D[name] = Bob

  • Сортировка по ключам: циклы for

  • Ks = D.keys()

  • Математический анализ. 3е издание


    Скачать 4.86 Mb.
    Название3е издание
    АнкорМатематический анализ
    Дата04.02.2022
    Размер4.86 Mb.
    Формат файлаpdf
    Имя файлаpython_01.pdf
    ТипДокументы
    #351981
    страница17 из 98
    1   ...   13   14   15   16   17   18   19   20   ...   98
    Проверка выхода за границы
    Хотя списки не имеют фиксированного размера, язык Python все рав
    но не допускает возможности обращаться к несуществующим элемен
    там списка. Обращение к элементам списка по индексам, значения ко
    торых выходят за пределы списка, всегда является ошибкой:
    >>> L
    [123, 'spam', 'NI']
    >>> L[99]
    ...текст сообщения об ошибке опущен...
    IndexError: list index out of range
    >>> L[99] = 1
    ... текст сообщения об ошибке опущен...
    IndexError: list assignment index out of range
    В этом примере я специально допустил ошибку (особенно неприятную в языке C, который не выполняет проверку выхода за границы масси
    ва, как Python) и попытался выполнить присваивание за пределами списка. Вместо того, чтобы увеличить размер списка, интерпретатор
    Python сообщает об ошибке. Чтобы увеличить список, необходимо вос
    пользоваться таким методом, как append.
    Вложенные списки
    Одна из замечательных особенностей базовых типов языка Python со
    стоит в том, что они поддерживают возможность создания вложенных конструкций произвольной глубины и в любых комбинациях (напри
    мер, можно создать список, содержащий словарь, который содержит другой список, и т. д.). Одно из очевидных применений этой особенно
    сти – представление матриц, или «многомерных массивов» в языке Py
    thon. Делается это с помощью списка, содержащего вложенные списки:
    >>> M = [[1, 2, 3], # Матрица 3
    ×3 в виде вложенных списков
    [4, 5, 6],

    126
    Глава 4. Введение в типы объектов языка Python
    [7, 8, 9]]
    >>> M
    [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    Здесь мы реализовали список, состоящий из трех других списков.
    В результате была получена матрица чисел 3
    ×3. Обращаться к такой структуре можно разными способами:
    >>> M[1] # Получить строку 2
    [4, 5, 6]
    >>> M[1][2] # Получить строку 2, а затем элемент 3 в этой строке
    6
    Первая операция в этом примере возвращает вторую строку целиком,
    а вторая – третий элемент в этой строке. Соединение операций индек
    сирования позволяет все дальше и дальше погружаться вглубь вло
    женной структуры объектов.
    1
    Дополнительные операции над списками
    Помимо обычных операций над последовательностями и методов спи
    сков, Python предоставляет возможность выполнять более сложные операции над списками, известные как выражения генераторов спи+
    сков
    (list comprehension expression), которые представляют эффектив
    ный способ обработки таких структур, как наша матрица. Предполо
    жим, например, что нам требуется извлечь из нашей матрицы второй столбец. Строку легко можно получить, выполнив операцию индекси
    рования, потому что матрица хранится в виде строк, однако, благода
    ря генераторам списков, получить столбец ничуть не сложнее:
    >>> col2 = [row[1] for row in M] # Выбирает элементы второго столбца
    >>> col2
    [2, 5, 8]
    >>> M # Матрица не изменилась
    [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    Генераторы списков следуют традиции системы представления мно
    жеств; они позволяют создавать новые списки, выполняя выражение для каждого элемента в последовательности, по одному за раз, слева
    1
    Такая организация матриц вполне пригодна для решения небольших за
    дач, но для реализации более сложных программ числовой обработки ин
    формации желательно использовать специализированные расширения, на
    пример NumPy. Такого рода инструменты позволяют хранить и обрабаты
    вать матрицы намного эффективнее, чем такая структура, реализованная в виде вложенных списков. Как уже говорилось, расширение NumPy пре
    вращает Python в свободный и более мощный эквивалент системы MatLab,
    и такие организации, как NASA, Los Alamos и JPMorgan Chase используют его для решения научных и финансовых задач. Дополнительную информа
    цию об этом расширении вы без труда найдете в Сети.

    Словари
    127
    направо. Генераторы списков заключены в квадратные скобки (чтобы отразить тот факт, что они создают список) и составлены из выражения и конструкции цикла, которые используют одно и то же имя перемен
    ной (в данном случае row). В предыдущем примере генератор списков интерпретируется так: «Получить элементы row[1] из каждой строки матрицы M и создать из них новый список». Результатом является но
    вый список, содержащий значения из второго столбца матрицы.
    На практике генераторы списков могут приобретать еще более слож
    ную форму:
    >>> [row[1] + 1 for row in M] # Добавить 1 к каждому элементу в столбце 2
    [3, 6, 9]
    >>> [row[1] for row in M if row[1] % 2 == 0] # Отфильтровать нечетные значения
    [2, 8]
    Первая операция в этом примере прибавляет 1 к значениям всех ото
    бранных элементов, а вторая использует условный оператор if для ис
    ключения из результата нечетных чисел с помощью операции деления по модулю – % (остаток от деления). Генераторы списков, применяе
    мые к спискам, возвращают в качестве результатов новые списки, но могут использоваться и для любых других объектов, допускающих выполнение итераций, например, ниже показано использование гене
    ратора списков для обхода жестко заданного в программном коде спи
    ска координат и строк:
    >>> diag = [M[i][i] for i in [0, 1, 2]] # Выборка элементов диагонали матрицы
    >>> diag
    [1, 5, 9]
    >>> doubles = [c * 2 for c in 'spam'] # Дублирование символов в строке
    >>> doubles
    ['ss', 'pp', 'aa', 'mm']
    Генераторы списков, на мой взгляд, достаточно сложная тема, чтобы говорить о них здесь более подробно. Главная цель этого краткого обзо
    ра состоит в том, чтобы проиллюстрировать наличие как простых, так и очень сложных инструментов в арсенале Python. Генераторы списков можно и не использовать, но на практике они оказываются очень удоб
    ными и нередко обеспечивают более высокую производительность при работе со списками. Кроме того, их можно применять к любым другим последовательностям в языке Python, а также к некоторым другим ти
    пам, которые не являются последовательностями. Мы еще будем гово
    рить об этих выражениях далее, в этой книге.
    Словари
    Словари в языке Python – это нечто совсем иное (по выражению Монти
    Пайтона), они вообще не являются последовательностями, это то, что известно, как отображения. Отображения – это коллекции объектов,

    128
    Глава 4. Введение в типы объектов языка Python но доступ к ним осуществляется не по определенным смещениям от начала коллекции, а по ключам. В действительности отображения во
    обще не подразумевают какоголибо упорядочения элементов по их позиции, они просто отображают ключи на связанные с ними значе
    ния. Словари – единственный тип отображения в наборе базовых объ
    ектов Python – также относятся к классу изменяемых объектов: они могут изменяться непосредственно, и в случае необходимости могут увеличиваться и уменьшаться в размерах, подобно спискам.
    Операции отображения
    Когда словарь определяется как литерал, программный код определе
    ния заключается в фигурные скобки и состоит из последовательности пар «ключ: значение». Словари удобно использовать всегда, когда воз
    никает необходимость связать значения с ключами, например чтобы описать свойства чеголибо. В качестве примера рассмотрим следую
    щий словарь, состоящий из трех элементов (с ключами «food» (про
    дукт питания), «quantity» (количество) и «color» (цвет)):
    >>> D = {'food': 'Spam', 'quantity': 4, 'color': 'pink'}
    Мы можем обращаться к элементам этого словаря по ключам и изме
    нять значения, связанные с ключами. Для доступа к элементам словаря используется тот же синтаксис, который используется для обращения к элементам последовательностей, только в квадратных скобках указы
    вается не смещение относительно начала последовательности, а ключ:
    >>> D['food'] # Получить значение, связанное с ключом 'food'
    'Spam'
    >>> D['quantity'] += 1 # Прибавить 1 к значению ключа 'quantity'
    >>> D
    {'food': 'Spam', 'color': 'pink', 'quantity': 5}
    Несмотря на то что форма определения словаря в виде литерала, заклю
    ченного в фигурные скобки, достаточно наглядна, на практике чаще встречаются другие способы создания словарей. Следующий пример начинается с создания пустого словаря, который затем заполняется по одному ключу за раз. В отличие от списков, не допускающих присваи
    вания значений отсутствующим элементам, присваивание значения по несуществующему ключу в словаре приводит к созданию этого ключа:
    >>> D = {}
    >>> D['name'] = 'Bob' # В результате присваивания создается ключ
    >>> D['job'] = 'dev'
    >>> D['age'] = 40
    >>> D
    {'age': 40, 'job': 'dev', 'name': 'Bob'}
    >>> print D['name']
    Bob

    Словари
    129
    В этом примере ключи словаря играют роль имен полей в записи, кото
    рая описывает некоторого человека. В других приложениях словари могут использоваться для замены операций поиска, поскольку обра
    щение к элементу словаря по ключу обычно выполняется быстрее, чем поиск, реализованный на языке Python.
    Еще раз о вложенности
    В предыдущем примере словарь использовался для описания гипоте
    тической персоны с помощью трех ключей. Теперь предположим, что информация имеет более сложную структуру. Возможно, придется за
    писать имя и фамилию, а также несколько названий должностей, за
    нимаемых одновременно. Это приводит к необходимости использова
    ния вложенных объектов Python. Словарь в следующем примере опре
    делен в виде литерала и имеет более сложную структуру:
    >>> rec = {'name': {'first': 'Bob', 'last': 'Smith'},
    'job': ['dev', 'mgr'],
    'age': 40.5}
    Здесь мы опять имеем словарь, содержащий три ключа верхнего уров
    ня (ключи «name» (имя), «job» (должность) и «age» (возраст)), однако значения имеют более сложную структуру: для описания имени челове
    ка используется вложенный словарь, чтобы обеспечить поддержку имен, состоящих из нескольких частей, и для перечисления занимае
    мых должностей используется вложенный список, что обеспечит воз
    можность расширения в будущем. К компонентам этой структуры мож
    но обращаться почти так же, как мы делали это в случае с матрицей, но на этот раз вместо числовых индексов мы используем ключи словаря:
    >>> rec['name'] # 'Name' – это вложенный словарь
    {'last': 'Smith', 'first': 'Bob'}
    >>> rec['name']['last'] # Обращение к элементу вложенного словаря
    'Smith'
    >>> rec['job'] # 'Job' – это вложенный список
    ['dev', 'mgr']
    >>> rec['job'][ 1] # Обращение к элементу вложенного списка
    'mgr'
    >>> rec['job'].append('janitor') # Расширение списка должностей Боба (Bob)
    >>> rec
    {'age': 40.5, 'job': ['dev', 'mgr', 'janitor'], 'name': {'last': 'Smith',
    'first': 'Bob'}}
    Обратите внимание, как последняя операция в этом примере выполня
    ет расширение вложенного списка. Так как список должностей – это от
    дельный от словаря участок в памяти, он может увеличиваться и умень
    шаться без какихлибо ограничений (размещение объектов в памяти будет обсуждаться позже, в этой же книге).

    130
    Глава 4. Введение в типы объектов языка Python
    Основная цель демонстрации этого примера состоит в том, чтобы пока
    зать вам гибкость базовых типов данных в языке Python. Здесь вы мо
    жете видеть, что возможность вложения позволяет легко воспроизво
    дить достаточно сложные структуры данных. Для создания подобной структуры на языке C потребовалось бы приложить больше усилий и написать больше программного кода: нам пришлось бы описать и объ
    явить структуры и массивы, заполнить их значениями, связать их меж
    ду собой и т. д. В языке Python все это делается автоматически – запуск выражения приводит к созданию всей структуры вложенных объектов.
    Фактически, это одно из основных преимуществ языков сценариев, та
    ких как Python.
    Так же как и в низкоуровневых языках программирования, мы могли бы выполнить освобождение памяти, занимаемой объектами, которые стали не нужны. В языке Python память освобождается автоматиче
    ски, когда теряется последняя ссылка на объект, например в случае присваивания переменной какоголибо другого значения:
    >>> rec = 0 # Теперь память, занятая объектом, будет освобождена
    С технической точки зрения, интерпретатор Python обладает такой особенностью, как сборка мусора, благодаря которой в ходе выполне
    ния программы производится освобождение неиспользуемой памяти,
    что освобождает нас от необходимости предусматривать специальные действия в программном коде. Интерпретатор освобождает память сразу же, как только будет ликвидирована последняя ссылка на объ
    ект. С работой этого механизма мы познакомимся далее, в этой же книге, а пока достаточно знать, что вы можете работать с объектами,
    не беспокоясь о выделении или освобождении памяти для них.
    1
    Сортировка по ключам: циклы for
    Будучи отображениями, как мы уже видели, словари поддерживают доступ к элементам только по ключам. Однако они кроме того поддер
    живают ряд специфических для данного типа операций, реализован
    ных в виде методов, которые удобно использовать в разных случаях.
    Как уже упоминалось ранее, изза того, что словари не являются после
    довательностями, они не предусматривают какойлибо надежный спо
    соб упорядочения позиций элементов. Это означает, что если мы созда
    дим словарь и попытаемся вывести его, порядок следования ключей при выводе может не совпадать с порядком, в каком они определялись:
    1
    В качестве примечания: имейте в виду, что запись rec, которую мы создали здесь, в действительности может быть записью в базе данных, если бы мы использовали систему хранения объектов Python – простейший способ хранения объектов Python в файлах или в базах данных, обеспечивающих доступ по ключу. Мы не будем здесь углубляться в подробности, а за допол
    нительной информацией по этому вопросу обращайтесь к модулям Python –
    pickle и shelve.

    Словари
    131
    >>> D = {'a': 1, 'b': 2, 'c': 3}
    >>> D
    {'a': 1, 'c': 3, 'b': 2}
    Как же быть, если нам действительно потребуется упорядочить эле
    менты словаря? В наиболее общем случае мы могли бы получить спи
    сок всех ключей словаря методом keys, отсортировать их с помощью метода списка sort и затем выполнить обход значений в цикле for:
    >>> Ks = D.keys() # Неупорядоченный список ключей
    >>> Ks
    ['a', 'c', 'b']
    >>> Ks.sort() # Сортировка списка ключей
    >>> Ks
    ['a', 'b', 'c']
    >>> for key in Ks: # Обход отсортированного списка ключей
    print key, '=>', D[key]
    a => 1
    b => 2
    c => 3
    Этот процесс, состоящий из трех этапов, в последних версиях Python можно упростить до единственной операции, как будет показано в по
    следующих главах, с помощью новой встроенной функции sorted
    (функция sorted сортирует объекты разных типов и возвращает их):
    >>> D
    {'a': 1, 'c': 3, 'b': 2}
    >>> for key in sorted(D):
    print key, '=>', D[key]
    a => 1
    b => 2
    c => 3
    Этот пример может служить поводом для знакомства с циклом for язы
    ка Python. Цикл for представляет собой самый простой и эффективный способ произвести обход всех элементов в последовательности и выпол
    нить блок программного кода для каждого из элементов. Переменная цикла, определяемая пользователем (в данном случае key), служит для ссылки на текущий элемент. В этом примере выводятся ключи и значе
    ния несортированного словаря, в отсортированном по ключам виде.
    Цикл for и родственный ему цикл while – это основные способы реализа
    ции повторяющихся действий в сценариях. Однако в действительности цикл for, так же как и родственные ему генераторы списков
    (с которыми мы познакомились выше), является операцией над после
    довательностью. Он способен работать с любыми объектами, являющи
    мися последовательностями, а также с некоторыми объектами, которые последовательностями не являются. Ниже приводится пример обхода всех символов в строке и вывод их в верхнем регистре:

    132
    Глава 4. Введение в типы объектов языка Python
    >>> for c in 'spam':
    print c.upper()
    S
    P
    A
    M
    Инструкции циклов мы рассмотрим позднее, в этой же книге.
    Итерации и оптимизация
    Если цикл for выглядит похожим на генераторы списков, введенные ранее, следовательно, оба эти инструмента должны представлять собой универсальные средства выполнения итераций. Фактически обе конст
    рукции способны работать с любыми объектами, которые поддержива
    ют протокол итераций – идею, недавно появившуюся в Python, кото
    рая по сути подразумевает наличие в памяти последовательности или объекта, который генерирует по одному элементу в контексте выполне
    ния итерации. Именно поэтому функция sorted, которая использова
    лась в предыдущем разделе, способна работать со словарем непосредст
    венно – нам не требуется вызывать метод keys для получения последо
    вательности, потому что словари поддерживают выполнение итераций.
    О протоколе итераций я расскажу позднее, в этой же книге. А пока просто запомните, что любой генератор списков, такой, как показано ниже, который вычисляет квадраты чисел в списке:
    >>> squares = [x ** 2 for x in [1, 2, 3, 4, 5]]
    >>> squares
    [1, 4, 9, 16, 25]
    всегда можно запрограммировать в виде эквивалентного цикла for, ко
    торый создает список с результатами, добавляя новые элементы в ходе выполнения итераций:
    >>> squares = []
    >>> for x in [1, 2, 3, 4, 5]: # Это список, который участвует в вычислениях
    squares.append(x ** 2)
    >>> squares
    [1, 4, 9, 16, 25]
    Однако генераторы списков обычно выполняются быстрее (примерно раза в два), что особенно важно для программ, обрабатывающих боль
    шие объемы данных. И тем не менее следует заметить, что оценка про
    изводительности – вещь очень хитрая в языке Python, потому что в про
    цессе разработки он продолжает оптимизироваться, и производитель
    ность тех или иных конструкций может изменяться от версии к версии.
    Главное правило, которому желательно следовать при использовании языка Python, – это простота и удобочитаемость программного кода,
    а проблему производительности следует рассматривать во вторую оче
    редь, уже после того, как будет создана работоспособная программа

    Словари
    1   ...   13   14   15   16   17   18   19   20   ...   98


    написать администратору сайта