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

  • Придется держать в уме: ООП глазами специалистов

  • Обработка исключений: краткий обзор

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


    Скачать 4.86 Mb.
    Название3е издание
    АнкорМатематический анализ
    Дата04.02.2022
    Размер4.86 Mb.
    Формат файлаpdf
    Имя файлаpython_01.pdf
    ТипДокументы
    #351981
    страница85 из 98
    1   ...   81   82   83   84   85   86   87   88   ...   98
    695
    class Customer:
    def __init__(self) # Инициализирует название блюда
    # значением None
    def placeOrder(self, foodName, employee) # Передает заказ официанту
    def printFood(self) # Выводит название блюда
    class Employee:
    def takeOrder(self, foodName) # Возвращает блюдо с указанным названием
    class Food:
    def __init__(self, name) # Сохраняет название блюда
    Имитация заказа работает следующим образом:
    a. Конструктор класса Lunch должен создать и встроить экземпляр класса Customer и экземпляр класса Employee, кроме того, экспор
    тировать метод с именем order. При вызове этот метод должен имитировать прием заказа у клиента (Customer) вызовом метода placeOrder
    . Метод placeOrder класса Customer должен в свою оче
    редь имитировать получение блюда (новый объект Food) у офици
    анта (Employee) вызовом метода takeOrder класса Employee.
    b. Объекты типа Food должны сохранять строку с названием блю
    да (например, «буррито»), которое передается через Lunch.order в Customer.placeOrder, затем в Employee.takeOrder и, наконец,
    в конструктор класса Food. Кроме того, класс Lunch должен еще экспортировать метод result, который предлагает клиенту (Cus
    tomer
    ) вывести название блюда, полученного от официанта (Em
    ployee
    ) в результате выполнения заказа (этот метод может ис
    пользоваться для проверки имитации).
    Обратите внимание: экземпляр класса Lunch должен передавать клиенту (Customer) либо экземпляр класса Employee (официант), либо себя самого, чтобы клиент (Customer) мог вызвать метод официанта
    (Employee).
    Поэкспериментируйте с получившимися классами в интерактив
    ной оболочке, импортируя класс Lunch и вызывая его метод order,
    чтобы запустить имитацию, а также метод result, чтобы проверить,
    что клиент (Customer) получил именно то, что заказывал. При жела
    нии можете добавить в файл с классами программный код самотес
    тирования, используя прием с атрибутом __name__ из главы 21.
    В этой имитации активность проявляет клиент (Customer); как бы вы изменили свои классы, чтобы инициатором взаимодействий ме
    жду клиентом и официантом был официант (Employee)?
    8. Классификация животных в зоологии. Изучите дерево классов,
    представленное на рис. 26.1. Напишите шесть инструкций class,
    которые моделировали бы эту модель классификации средствами наследования в языке Python. Затем добавьте к каждому из классов метод speak, который выводил бы уникальное сообщение, и метод reply в суперклассе Animal, являющемся вершиной иерархии, кото
    рый просто вызывал бы self.speak, чтобы вывести текст сообщения,

    696
    Глава 26. Дополнительные возможности классов характерного для каждой категории в подклассах, расположенных ниже (это вынудит начинать поиск в дереве наследования от экзем
    пляра self). Наконец, удалите метод speak из класса Hacker, чтобы для него по умолчанию выводилось сообщение, унаследованное от класса выше. Когда вы закончите, ваши классы должны работать следующим образом:
    % python
    >>> from zoo import Cat, Hacker
    >>> spot = Cat()
    >>> spot.reply() # Animal.reply; вызывается Cat.speak meow
    >>> data = Hacker() # Animal.reply; вызывается Primate.speak
    >>> data.reply()
    Hello world!
    9. Сценка с мертвым попугаем. Изучите схему встраивания объек
    тов, представленную на рис. 26.2. Напишите набор классов на язы
    ке Python, которые реализовали бы эту схему средствами компози
    ции. Класс Scene (сцена) должен определять метод action и встраи
    вать в себя экземпляры классов Customer (клиент), Clerk (клерк)
    и Parrot (попугай), каждый из которых должен определять метод line
    , выводящий уникальное сообщение. Встраиваемые объекты могут наследовать один общий суперкласс, определяющий метод line
    , который просто выводит текст указанного ему сообщения, или определяют собственные реализации метода line. В конечном итоге ваши классы должны действовать, как показано ниже:
    % python
    >>> import parrot
    >>> parrot.Scene().action() # Активировать встроенные объекты
    customer: "that's one exbird!"
    clerk: "no it isn't..."
    parrot: None
    Hacker (хакер)
    Animal (животное)
    Mammal (млекопитающее)
    Cat (кошка)
    Dog (собака)
    Primate (примат)
    Рис. 26.1. Классификация животных в зоологии, составленная из классов,
    связанных в дерево наследования. Класс Animal имеет общий метод «reply»,
    но каждый из классов имеет свой собственный метод «speak», который
    вызывается методом «reply»

    Закрепление пройденного
    697
    Parrot (попугай)
    Scene (сцена)
    Customer (клиент)
    Clerk (клерк)
    action
    line
    Рис. 26.2. Составная сцена, представленная управляющим классом (Scene),
    который встраивает и управляет экземплярами трех других классов
    (Customer, Clerk, Parrot). Встроенные экземпляры классов могут также
    участвовать в иерархии наследования – композиция и наследование часто
    являются одинаково полезными способами организации классов с целью
    обеспечения возможности повторного использования программного кода
    Придется держать в уме:
    ООП глазами специалистов
    Когда я рассказываю о классах в языке Python, я все время обна
    руживаю, что в середине лекции о классах люди, имевшие опыт
    ООП в прошлом, заметно активизируются, а те, кто такого опы
    та не имеет, начинают сникать (или вообще засыпают). Преиму
    щества этой технологии не так очевидны.
    В такой книге, как эта, у меня есть уникальная возможность включить обзорный материал, которой я воспользовался в гла
    ве 22 – настоятельно рекомендую вам перечитать эту главу, как только вам начинает казаться, что ООП – это всего лишь неко
    торое украшение в программировании.
    В реальной аудитории, чтобы привлечь (и удержать) внимание начинающих программистов, я обычно останавливаюсь и спра
    шиваю у присутствующих опытных специалистов, почему они используют ООП. Ответы, которые они дают, могут пролить свет на цели, которые преследует ООП для тех, кто плохо знаком с этой темой.
    Ниже приводятся лишь самые общие причины, побуждающие использовать ООП, которые были высказаны моими студентами за эти годы:
    Повторное использование программного кода
    Это самая простая (и самая основная) причина использования
    ООП. Возможность наследования в классах позволяет про
    граммисту писать программы, адаптируя существующий программный код, а не писать каждый новый проект с самого начала.

    698
    Глава 26. Дополнительные возможности классов
    Инкапсуляция
    Сокрытие деталей реализации за интерфейсом объекта предо
    храняет пользователей класса от необходимости изменять свой программный код.
    Организация
    Классы предоставляют новые локальные области видимости,
    которые минимизируют вероятность конфликтов имен. Кро
    ме того, они обеспечивают место для естественного размеще
    ния программного кода реализации и управления состоянием объекта.
    Поддержка
    Классы обеспечивают естественное разделение программного кода, что позволяет уменьшить его избыточность. Благодаря организации и возможности повторного использования про
    граммного кода в случае необходимости бывает достаточно изменить всего одну копию программного кода.
    Непротиворечивость
    Классы и возможность наследования позволяют реализовать общие интерфейсы и, следовательно, обеспечить единообразие вашего программного кода – такой код легко поддается отлад
    ке, выглядит более осмысленно и прост в сопровождении.
    Полиморфизм
    Это скорее свойство ООП, чем причина его использования, но благодаря поддержке общности программного кода полимор
    физм делает код более гибким, расширяет область его приме
    нения и, следовательно, увеличивает его шансы на повторное использование.
    Другие
    И, конечно, причина номер один состоит в том, что упомина
    ние о владении приемами ООП увеличивает шанс быть при
    нятым на работу! (Согласен, я привел эту причину в шутку,
    но, если вы собираетесь работать на ниве программирования,
    для вас очень важно будет иметь знакомство с ООП.)
    И в заключение, не забывайте, что я говорил в начале шестой части: вы не сможете полностью оценить достоинства ООП, пока не будете использовать его какоето время. Выберите себе проект,
    изучите большие примеры, поработайте над упражнениями – это заставит вас попотеть над объектноориентированным про
    граммным кодом, но оно стоит того.

    VII
    Исключения и инструменты

    27
    Основы исключений
    В последней части книги рассказывается об исключениях, которые, по сути, являются событиями, способными изменить ход выполнения программы. Исключения в языке Python возбуждаются автоматиче
    ски, когда программный код допускает ошибку, а также могут возбу
    ждаться и перехватываться самим программным кодом. Обрабатыва
    ются исключения четырьмя инструкциями. Эти инструкции мы и бу
    дем изучать в данной части книги. Первая из инструкций имеет две разновидности (ниже они перечислены отдельно), а последняя – явля
    ется дополнительным расширением до выхода версии Python 2.6: try/except
    Перехватывает исключения, возбужденные интерпретатором или вашим программным кодом, и выполняет восстановительные опе
    рации.
    try/finally
    Выполняет заключительные операции независимо от того, возник
    ло ли исключение или нет.
    raise
    Дает возможность возбудить исключение программно.
    assert
    Дает возможность возбудить исключение программно, при выпол
    нении определенного условия.
    with/as
    Реализует менеджеры контекста в версии Python 2.6 и выше (в вер
    сии 2.5 является дополнительным расширением).
    Эта тема была оставлена напоследок потому, что для работы с исклю
    чениями необходимо знание классов. Тем не менее, за несколькими

    702
    Глава 27. Основы исключений исключениями (преднамеренная игра слов), как будет показано ниже,
    обработка исключений в языке Python выполняется очень просто, по
    тому что они интегрированы непосредственно в сам язык, как и другие высокоуровневые средства.
    Одно техническое примечание перед началом: после выхода первого издания этой книги в исключениях произошли два изменения – пред
    ложение finally может теперь присутствовать в инструкции try вместе с предложениями except и else, а исключения, определяемые програм
    мой, теперь должны быть экземплярами классов, а не простыми стро
    ками. В этом издании я опишу и старый, и новый способы работы с ис
    ключениями, потому что в существующем программном коде вам еще часто будут встречаться изначальные приемы. Попутно я расскажу,
    какими путями шло развитие в этой области. Я также опишу новую инструкцию with несмотря на то, что ее официальное появление ожи
    дается только в следующем выпуске Python.
    Зачем нужны исключения?
    В двух словах, исключения позволяют перепрыгнуть через фрагмент программы произвольной длины. Рассмотрим пример с машиной по приготовлению пиццы, о которой говорилось ранее в этой книге.
    Предположим, что мы более чем серьезно отнеслись к этой идее и дей
    ствительно построили такую машину. Чтобы приготовить пиццу, наш кулинарный автомат должен выполнить программу, написанную на языке Python: она должна принимать заказ, приготовить тесто, вы
    брать добавки, выпечь основу и т. д.
    Теперь предположим, что чтото пошло совсем не так во время «выпе
    кания основы». Возможно, сломалась печь или, возможно, наш робот ошибся в расчетах расстояния до печи и воспламенился. Совершенно очевидно, что нам необходимо предусмотреть быстрый переход к про
    граммному коду, который быстро обрабатывает такие ситуации. Кроме того, поскольку в таких необычных условиях у нас нет никакой надеж
    ды на успешное окончание процесса приготовления пиццы, мы могли бы также вообще отказаться от выполнения всего плана целиком.
    Это именно то, что позволяют делать исключения: программа может перейти к обработчику исключения за один шаг, отменив все вызовы функций. Исключение – это своего рода «суперgoto».
    1
    Обработчик ис
    ключений (инструкция try) ставит метку и выполняет некоторый про
    граммный код. Если затем гденибудь в программе возникает исключе
    1
    Если вы использовали язык C, вам будет интересно узнать, что исключе
    ния в языке Python немного похожи на стандартную для языка C пару функций setjmp/longjmp: инструкция try действует как функция setjmp,
    а инструкция raise как longjmp. Только в языке Python исключения основа
    ны на объектах и являются стандартной частью модели исполнения.

    Зачем нужны исключения?
    703
    ние, интерпретатор немедленно возвращается к метке, отменяя все ак
    тивные вызовы функций, которые были произведены после установки метки. Код в обработчике исключения может соответствующим обра
    зом отреагировать на ситуацию (вызвать пожарных, например). Кроме того, переход к обработчику исключения выполняется немедленно, по
    этому обычно нет никакой необходимости проверять коды возврата ка
    ждой вызванной функции, которая могла потерпеть неудачу.
    Назначение исключений
    В программах на языке Python исключения могут играть разные роли.
    Ниже приводятся некоторые из них, являющиеся наиболее типичными:
    Обработка ошибок
    Интерпретатор возбуждает исключение всякий раз, когда обнаружи
    вает ошибку во время выполнения программы. Программа может пе
    рехватывать такие ошибки и обрабатывать их или просто игнориро
    вать. Если ошибка игнорируется, интерпретатор выполняет дейст
    вия, предусмотренные по умолчанию, – останавливает выполнение программы и выводит сообщение об ошибке. Если такое поведение по умолчанию является нежелательным, можно добавить инструкцию try
    , которая позволит перехватывать обнаруженные ошибки и про
    должить выполнение программы после инструкции try.
    Уведомления о событиях
    Исключения могут также использоваться для уведомления о насту
    плении некоторых условий, что устраняет необходимость переда
    вать кудалибо флаги результата или явно проверять их. Например,
    функция поиска может возбуждать исключение в случае неудачи,
    вместо того чтобы возвращать целочисленный признак в виде ре
    зультата (и надеяться, что этот признак всегда будет интерпретиро
    ваться правильно).
    Обработка особых ситуаций
    Некоторые условия могут наступать так редко, что было бы слиш
    ком расточительно предусматривать проверку наступления таких условий с целью их обработки. Нередко такие проверки необычных ситуаций можно заменить обработчиками исключений.
    Заключительные операции
    Как будет показано далее, инструкция try/finally позволяет гаран
    тировать выполнение завершающих операций независимо от нали
    чия исключений.
    Необычное управление потоком выполнения
    И, наконец, так как исключения это своего рода оператор «goto»,
    их можно использовать как основу для экзотического управления потоком выполнения программы. Например, обратная трассировка не является частью самого языка, но она может быть реализована

    704
    Глава 27. Основы исключений с помощью исключений и некоторой логики поддержки, выпол
    няющей раскручивание операций присваивания.
    1
    Далее в этой части книги мы увидим примеры этих типичных приме
    нений. А пока начнем с обзора средств языка Python, предназначен
    ных для обработки исключений.
    Обработка исключений: краткий обзор
    В сравнении с некоторыми другими основными возможностями, кото
    рые рассматривались в этой книге, исключения в языке Python пред
    ставляют собой чрезвычайно легкий инструмент. Поскольку они так просты, перейдем сразу к первому примеру. Предположим, что мы пи
    шем следующую функцию:
    >>> def fetcher(obj, index):
    ... return obj[index]
    Эта функция делает не так много – она просто извлекает элемент из объекта по заданному индексу. При нормальном стечении обстоя
    тельств она возвращает результат:
    >>> x = 'spam'
    >>> fetcher(x, 3) # Все равно, что x[3]
    'm'
    Однако, если передать функции индекс, выходящий за пределы стро
    ки, то при попытке выполнить выражение obj[index] будет возбужде
    но исключение. Обнаруживая выход за пределы последовательности,
    интерпретатор сообщает об этом, возбуждая встроенное исключение
    IndexError
    :
    >>> fetcher(x, 4)
    Traceback (most recent call last):
    File "", line 1, in ?
    File "", line 2, in fetcher
    IndexError: string index out of range
    (IndexError: выход индекса за пределы строки)
    Поскольку наш программный код не перехватывает это исключение яв
    но, оно возвращает выполнение на верхний уровень программы и вызы
    1
    Настоящая обратная трассировка – это довольно сложная тема, и данная возможность не является частью самого языка Python (даже с появлением функцийгенераторов в версии 2.2), поэтому я не буду больше говорить об этом. Грубо говоря, обратная трассировка отменяет все вычисления перед переходом – исключения этого не делают (то есть в переменных, которым было выполнено присваивание между моментом выполнения инструкции try и до момента возбуждения исключения, прежние значения не восста
    навливаются). Если вам любопытна эта тема, обращайтесь к книгам по ис
    кусственному интеллекту или языкам программирования Prolog или Icon.

    Обработка исключений: краткий обзор
    705
    вает обработчик исключений по умолчанию, который просто выводит стандартное сообщение об ошибке. К настоящему моменту вы наверняка видели в своих программах подобные сообщения об ошибках. Они вклю
    чают тип исключения, а также диагностическую информацию – список строк и функций, которые были активны в момент появления исключе
    ния. При работе в интерактивной оболочке файлом является «stdin»
    (стандартный поток ввода) или «pyshell» (в IDLE), поэтому в данном случае номера строк не несут скольконибудь полезной информации.
    В настоящей программе, запущенной не в интерактивной оболочке,
    обработчик кроме этого по умолчанию завершает работу программы.
    Такое действие имеет смысл для простых сценариев – как правило,
    ошибки в таких сценариях должны быть фатальными и лучшее, что можно сделать при их появлении, – это ознакомиться с текстом сооб
    щения. Но иногда это совсем не то, что нам требуется. Например, сер
    верные программы обычно должны оставаться активными даже после появления внутренних ошибок. Если вам требуется избежать реакции на исключение по умолчанию, достаточно просто перехватить исклю
    чение, обернув вызов функции инструкцией try:
    >>>
    1   ...   81   82   83   84   85   86   87   88   ...   98


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