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

  • Зачем нужны классы

  • Поиск унаследованных атрибутов

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


    Скачать 4.86 Mb.
    Название3е издание
    АнкорМатематический анализ
    Дата04.02.2022
    Размер4.86 Mb.
    Формат файлаpdf
    Имя файлаpython_01.pdf
    ТипДокументы
    #351981
    страница68 из 98
    1   ...   64   65   66   67   68   69   70   71   ...   98
    558
    Глава 21. Дополнительные возможности модулей в упражнении 1 или 3, и попробуйте импортировать его как пакет,
    инструкцией import mypkg.mymod.
    Вам потребуется добавить файл __init__.py в каталог, куда был по
    мещен ваш модуль. Это упражнение должно работать на всех основ
    ных платформах Python (это одна из причин, почему в языке Py
    thon в качестве разделителя компонентов пути используется сим
    вол «.»). Каталог пакета может быть простым подкаталогом в ва
    шем рабочем каталоге – в этом случае он будет обнаружен интерпретатором при поиске в домашнем каталоге и вам не потре
    буется настраивать путь поиска. Добавьте какойнибудь программ
    ный код в __init__.py и посмотрите, будет ли он выполняться при каждой операции импортирования.
    6. Повторная загрузка. Поэкспериментируйте с возможностью по
    вторной загрузки модуля: выполните тесты, которые приводятся в примере changer.py в главе 19, многократно изменяя текст сообще
    ния и/или поведение модуля, без остановки интерактивного сеанса работы с интерпретатором Python. В зависимости от операционной системы файл модуля можно было бы редактировать в другом окне или, приостановив интерпретатор, редактировать модуль в том же окне (в UNIX комбинация клавиш CtrlZ обычно приводит к приос
    тановке текущего процесса, а команда fg – возобновляет его работу).
    7. Циклический импорт.
    1
    В разделе, где описываются проблемы, свя
    занные с рекурсивным импортом, импортирование модуля recur1
    вызывает появление ошибки. Но если перезапустить интерактив
    ный сеанс работы с интерпретатором и предварительно импортиро
    вать модуль recur2, ошибка не возникает – проверьте этот факт са
    ми. Как вы думаете, почему импортирование recur2 проходит без ошибок, а импортирование recur1 с ошибками? (Подсказка: интер
    претатор Python сохраняет новые модули во встроенной таблице
    (словаре) sys.modules перед их запуском, независимо от того, «завер
    шен» модуль или нет.) Теперь попробуйте запустить recur1 как са
    мостоятельный сценарий: python recur1.py. Получите ли вы ту же самую ошибку, которая возникает при импортировании recur1 в ин
    терактивной оболочке? Почему? (Подсказка: когда модули запус
    каются как самостоятельные программы, они не импортируются,
    поэтому здесь возникает тот же эффект, как и при импортировании recur2
    в интерактивной оболочке, – recur2 является первым импор
    тируемым модулем.) Что произойдет, если запустить recur2 как са
    мостоятельный сценарий? Почему?
    1
    Обратите внимание, что циклическое импортирование чрезвычайно редко встречается на практике. Автор этой книги за десять лет работы с языком
    Python на практике сам не использовал и не сталкивался с циклическим импортом. Однако если вы в состоянии понять, в чем заключается пробле
    ма при использовании циклического импорта, это будет означать, что вы достаточно много знаете о семантике языка Python.

    VI
    Классы и ООП

    22
    ООП: общая картина
    До сих пор в этой книге мы использовали термин «объект» в общем смысле. В действительности весь программный код, написанный нами до сих пор, был основан на объектах (object+based) – везде в своих сце
    нариях мы передавали объекты, использовали их в выражениях, вы
    зывали их методы и т. д. Однако, чтобы наш программный код стал понастоящему объектноориентированным (object+oriented, ОО), на
    ши объекты должны участвовать в иерархии наследования.
    Начиная с этой главы, мы приступаем к исследованию классов в язы
    ке Python – программных компонентов, используемых для реализа
    ции новых типов объектов, поддерживающих наследование. Классы –
    это основные инструменты объектноориентированного программиро
    вания (ООП) в языке Python, поэтому в этой части книги мы попутно рассмотрим основы ООП. ООП предлагает другой, часто более эффек
    тивный подход к программированию, при котором мы разлагаем про
    граммный код на составляющие, чтобы снизить его избыточность,
    и пишем новые программы, адаптируя имеющийся программный код,
    а не изменяя существующий или создавая новый код.
    Классы в языке Python создаются с помощью новой для нас инструк
    ции: инструкции class. Как вы увидите, объекты, определяемые с по
    мощью классов, очень напоминают встроенные типы, которые мы изу
    чали ранее в этой книге. В действительности классы лишь применяют и дополняют понятия, которые мы уже рассмотрели. Грубо говоря –
    они представляют собой пакеты функций, которые в основном исполь
    зуют и обрабатывают объекты встроенных типов. Основное назначе
    ние классов состоит в том, чтобы создавать и манипулировать новыми объектами, а кроме того, они поддерживают механизм наследования –
    совсем иной способ адаптации программного кода и повторного его ис
    пользования, чем мы рассматривали ранее.

    562
    Глава 22. ООП: общая картина
    Одно предварительное замечание: ООП в языке Python является не
    обязательным к применению, и на первых порах вам не обязательно использовать классы. Многие задачи можно реализовать с помощью более простых конструкций, таких как функции, или даже просто программируя на верхнем уровне в сценарии. Поскольку использова
    ние классов требует некоторого предварительного планирования, они представляют больший интерес для тех, кто работает в стратегиче+
    ском
    режиме (участвует в долгосрочной разработке программных про
    дуктов), чем для тех, кто работает в тактическом режиме (где на раз
    работку дается очень короткое время).
    Однако, как вы увидите в этой части книги, классы являются одним из самых мощных инструментов в языке Python. При грамотном ис
    пользовании классы способны радикально сократить время, затрачи
    ваемое на разработку. Они также присутствуют в таких популярных инструментах, как Tkinter GUI API, поэтому для большинства про
    граммистов, использующих язык Python, знание основ работы с клас
    сами будет как минимум полезно.
    Зачем нужны классы?
    Помните, как я говорил вам, что «программы выполняют некоторые действия над чемто»? Проще говоря, классы – это всего лишь способ определить новое «чтото», они являются отражением реальных объ
    ектов в мире программ. Например, предположим, что мы решили реа
    лизовать гипотетическую машину по изготовлению пиццы, которую мы использовали в качестве примера в главе 15. Если реализовать ее на основе классов, мы могли бы смоделировать более близкое к реаль
    ности строение машины и взаимосвязь между ее механизмами. Полез
    ными здесь оказываются два аспекта ООП:
    Наследование
    Машина по изготовлению пиццы – это разновидность машин, по
    этому она обладает обычными свойствами, характерными для ма
    шин. В терминах ООП это называется «наследованием» свойств бо
    лее общей категории машин. Эти общие свойства необходимо реа
    лизовать всего один раз, после чего мы сможем использовать их для моделирования любых типов машин, которые нам потребуется соз
    дать в будущем.
    Композиция
    Машины по изготовлению пиццы состоят из множества компонен
    тов, которые все вместе работают как единое целое. Например, на
    шей машине необходимы манипуляторы, чтобы раскатывать тесто,
    двигатели, чтобы перемещаться к духовке, и т. д. На языке ООП на
    ша машина – это пример композиции; она содержит другие объек
    ты, которые активизируются для выполнения определенных дейст

    Зачем нужны классы?
    563
    вий. Каждый компонент может быть оформлен как класс, который определяет свое поведение и принципы взаимодействия.
    Общие идеи ООП, такие как наследование и композиция, применимы к любым приложениям, которые могут быть разложены на ряд объек
    тов. Например, в типичных программах с графическим интерфейсом сам интерфейс создается как набор визуальных элементов управления –
    кнопок, меток и т. д., которые рисуются на экране в тот момент, когда выполняется рисование их контейнеров (композиция). Кроме того, мы можем создать свои собственные визуальные элементы – кнопки с уникальными шрифтами, метки с новыми цветовыми схемами, ко
    торые будут представлять собой специализированные версии более об
    щих интерфейсных элементов (наследование).
    Если говорить более точно, с точки зрения программирования классы –
    это программные компоненты на языке Python, точно такие же, как функции и модули: они представляют собой еще один способ упаковки выполняемого кода и данных. Кроме того, классы определяют свои пространства имен, так же как и модули. Но в отличие от других про
    граммных компонентов, которые мы уже видели, классы имеют три важных отличия, которые делают их более полезными, когда дело до
    ходит до создания новых объектов:
    Множество экземпляров
    Классы по своей сути являются фабриками по созданию объектов.
    Каждый раз, когда вызывается класс, создается новый объект со своим собственным пространством имен. Каждый объект, создан
    ный из класса, имеет доступ к атрибутам класса и получает в свое распоряжение собственное пространство имен для своих собствен
    ных данных, отличных от данных других объектов.
    Адаптация через наследование
    Классы также поддерживают такое понятие ООП, как наследова
    ние, – мы можем расширять возможности класса, переопределяя его атрибуты за пределами самого класса. В более общем смысле классы могут создавать иерархии пространств имен, которые опре
    деляют имена для использования объектами, созданными из клас
    сов в иерархии.
    Перегрузка операторов
    Обеспечивая специальный протокол оформления методов, классы могут определять объекты, над которыми можно производить ка
    кието из операций, которые мы знаем по работе со встроенными типами. Например, объекты, созданные из классов, могут подвер
    гаться операции извлечения среза, конкатенации, извлечения эле
    ментов по их индексам и т. д. Язык Python предоставляет специ
    альные обработчики, которые могут использоваться классами для перехвата и реализации любой встроенной операции.

    564
    Глава 22. ООП: общая картина
    ООП с высоты 30 000 футов
    Прежде чем мы увидим, что все это означает в терминах программного кода, я хотел бы сказать несколько слов об общих идеях, лежащих в ос
    нове ООП. Если раньше вам не приходилось делать чтонибудь в объект
    ноориентированном стиле, некоторые термины в этой главе при первом знакомстве могут вам показаться немного сложными. Кроме того,
    смысл этих терминов может ускользать от вас, пока вы не получите воз
    можность познакомиться с тем, как программисты применяют их в крупных программах. ООП – это не только технология, но еще и опыт.
    Поиск унаследованных атрибутов
    Самое интересное, что ООП в языке Python проще в изучении и ис
    пользовании, чем в других языках программирования, таких как C++
    и Java. Будучи языком сценариев с динамической типизацией, Python ликвидирует синтаксическую перегруженность и сложность, свойст
    венные ООП в других языках. Фактически ООП в языке Python сво
    дится к выражению:
    object.attribute
    Мы использовали это выражение на протяжении всей книги для орга
    низации доступа к атрибутам модуля, вызова методов объектов и т. д.
    Однако, когда подобное выражение применяется к объекту, получен
    ному с помощью инструкции class, интерпретатор начинает поиск –
    поиск в дереве связанных объектов, который заканчивается, как толь
    ко будет встречено первое появление атрибута attribute. Когда в дело вступают классы, это выражение на языке Python можно перевести в следующее выражение на естественном языке:
    Найти первое вхождение атрибута attribute, просмотрев объект,
    а потом все классы выше него, снизу вверх и слева направо.
    Другими словами, выборка атрибутов производится в результате про
    стого поиска по дереву. Мы называем эту процедуру поиском в дереве
    наследования
    , потому что объекты, расположенные в дереве ниже, на
    следуют атрибуты, имеющиеся у объектов, расположенных в дереве выше. Так как поиск происходит в направлении снизу вверх, объекты в некотором смысле оказываются связаны в древовидную структуру,
    представляющую собой объединение всех атрибутов, определяемых всеми их родителями в дереве.
    В языке Python все это понимается буквально: с помощью программно
    го кода мы действительно создаем деревья связанных объектов, и ин
    терпретатор действительно поднимается вверх по дереву, пытаясь во время выполнения отыскать атрибуты всякий раз, когда мы использу
    ем выражение object.attribute. Чтобы было более понятно, на рис. 22.1
    приводится пример одного из таких деревьев.

    ООП с высоты 30 000 футов
    565
    На этом рисунке изображено дерево из пяти объектов, помеченных именами переменных. Каждый из этих объектов обладает набором ат
    рибутов. Если говорить более точно, это дерево связывает вместе три объекта классов (в овалах, C1, C2 и C3) и два объекта экземпляра (в пря
    моугольниках, I1 и I2) в иерархию наследования. Обратите внимание,
    что в модели объектов в языке Python классы и экземпляры порожда
    ются от двух разных типов объектов:
    Классы
    Играют роль фабрик экземпляров. Их атрибуты – данные и функ
    ции – обеспечивают поведение, то есть наследуются всеми экземп
    лярами, созданными от них (например, функция, вычисляющая зарплату служащего, исходя из часового тарифа).
    Экземпляры
    Представляют конкретные элементы программы. Их атрибуты хра
    нят данные, которые могут отличаться в конкретных объектах (на
    пример, номер социального страхования служащего).
    В терминах деревьев поиска экземпляры наследуют атрибуты своих классов, а классы наследуют атрибуты всех других классов, находя
    щихся в дереве выше.
    На рис. 22.1 можно продолжить категоризацию классов по относитель
    ным положениям овалов в дереве. Классы, расположенные в дереве вы
    ше (такие как C2 и C3), мы обычно называем суперклассами, а классы,
    расположенные ниже (такие как C1), называются подклассами.
    1
    Эти
    1
    В других книгах можно также встретить такие термины, как базовые клас+
    сы
    и дочерние классы, которые используются для обозначения суперклас
    сов и подклассов соответственно.
    C1
    C2
    C3
    I1
    I2
    .x
    .z
    .w
    .z
    .x
    .y
    .name
    .name
    Рис. 22.1. Дерево классов с двумя экземплярами внизу (I1 и I2), классом выше
    их (C1) и двумя суперклассами в самом верху (C2 и C3). Все эти объекты
    являются пространствами имен (пакетами переменных), а наследование
    означает просто поиск в дереве снизу вверх, цель которого – найти самое
    нижнее вхождение атрибута с требуемым именем. Программный код
    задает структуру таких деревьев

    566
    Глава 22. ООП: общая картина термины обозначают относительное положение в дереве и исполняе
    мые роли. Суперклассы реализуют поведение, общее для всех их под
    классов, но изза того, что поиск производится снизу верх, подклассы могут переопределять поведение, определяемое их суперклассами, пе
    реопределяя имена суперклассов ниже в дереве.
    Так как эти последние несколько слов отражают основную суть адапта
    ции программного обеспечения в ООП, давайте подробнее рассмотрим эту концепцию. Предположим, что мы создали дерево, приведенное на рис. 22.1, и затем пишем:
    I2.w
    Этот программный код демонстрирует использование механизма на
    следования. Так как это выражение вида object.attribute, оно приво
    дит к запуску поиска в дереве с рис. 22.1 – интерпретатор приступает к поиску атрибута w, начиная с I2, и движется вверх по дереву. В част
    ности, он будет просматривать объекты в следующем порядке:
    I2, C1, C2, C3
    и остановится, как только будет найден первый атрибут с таким име
    нем (или возбудит исключение, если атрибут w вообще не будет найден).
    В этом случае поиск будет продолжаться, пока не будет достигнут объ
    ект C3, поскольку атрибут w имеется только в этом объекте. Другими словами, имя I2.w в терминах автоматического поиска ищется как C3.w.
    В терминологии ООП это называется: I2 «наследует» атрибут w от C3.
    В конечном итоге два экземпляра наследуют от своих классов четыре атрибута: w, x, y и z. Другие атрибуты будут найдены в различных пу
    тях в дереве. Например:

    Для I1.x и I2.x атрибут x будет найден в C1, где поиск остановится,
    потому что C1 находится в дереве ниже, чем C2.

    Для I1.y и I2.y атрибут y будет найден в C1, где поиск остановится,
    потому что это единственное место, где он появляется.

    Для I1.z и I2.z атрибут z будет найден в C2, потому что C2 находится в дереве левее, чем C3.

    Для I2.name атрибут name будет найден в I2, в этом случае поиск по дереву вообще осуществляться не будет.
    Проследите эти пути поиска в дереве на рис. 22.1, чтобы понять, как выполняется поиск по дереву наследования в языке Python.
    Первый элемент в предыдущем списке является, пожалуй, самым важным, потому что C1 переопределяет атрибут x ниже в дереве, тем самым замещая версию атрибута, расположенную выше, в C2. Как вы увидите через мгновение, такие переопределения составляют основу адаптации программного обеспечения в ООП – переопределяя и заме
    щая атрибут, C1 эффективно изменяет свое поведение, унаследованное от своего суперкласса.

    ООП с высоты 30 000 футов
    567
    Классы и экземпляры
    Являясь отдельными типами объектов в модели языка Python, классы и экземпляры, которые мы объединили в иерархические деревья, вы
    полняют практически одну и ту же роль: каждый из этих типов слу
    жит некоторым представлением пространства имен – пакета пере
    менных и места, где определяются атрибуты. Если вследствие этого классы и экземпляры покажутся вам похожими на модули, то можно считать и так, но при этом объекты в деревьях классов содержат авто
    матически определяемые ссылки на другие объекты пространств имен,
    и классы соответствуют инструкциям, а не файлам.
    Основное различие между классами и экземплярами состоит в том, что классы представляют собой своего рода фабрики по производству экзем
    пляров. Например, в реалистичном приложении у нас мог бы быть класс
    Employee
    , которые определяет характеристики служащего, – из этого класса мы можем создавать фактические экземпляры класса Employee.
    Это еще одно различие между классами и модулями: у нас всегда име
    ется всего один экземпляр заданного модуля в памяти (именно по этой причине приходится перезагружать модуль, чтобы загрузить в память новый программный код), но в случае с классами можно создать столь
    ко экземпляров, сколько потребуется.
    В оперативном отношении у классов обычно имеются функции, присое
    диненные к ним (например, computeSalary), а у экземпляров – элементы данных, используемые функциями класса (например, hoursWorked).
    Фактически объектноориентированная модель не так сильно отлича
    ется от классической модели обработки данных, основанной на про+
    граммах
    и записях, в ООП экземпляры подобны записям с «данны
    ми», а классы – «программам», обрабатывающими эти записи. Однако в ООП имеется также понятие иерархии наследования, которая обес
    печивает более широкие возможности адаптации программного обес
    печения, чем более ранние модели.
    1   ...   64   65   66   67   68   69   70   71   ...   98


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