Книга на вашем родном языке 6 2 Переводы 7 1 Доступные переводы переводы 7 3 Предисловие 16
Скачать 0.72 Mb.
|
else : ( 'Создание резервной копии НЕ УДАЛОСЬ' ) 7 bug fixing – устранение «багов», исправление ошибок (прим.перев) 13.5. Четвёртая версия 105 A Byte of Python (Russian), Версия 2.02 Вывод: $ python3 backup_ver4.py Введите комментарий --> added new examples Резервная копия успешно создана в E:\Backup\20080702\202836_added_new_ , → examples.zip $ python3 backup_ver4.py Введите комментарий --> Резервная копия успешно создана в E:\Backup\20080702\202839.zip Как это работает: Теперь эта программа работает! Давайте просмотрим все улучшения, сделан- ные нами для версии 3. Мы запрашиваем пользовательский комментарий при помощи функции input , а затем проверяем, ввёл ли пользователь что-либо, определяя длину введённой строки функцией len . Если пользователь просто нажал ENTER , не вводя никакого текста (может быть, это было регулярное со- здание резервной копии, или никаких особых изменений внесено не было), мы продолжаем так же, как делали до сих пор. Если же комментарий был введён, он добавляется к имени zip-архива перед расширением .zip . Обратите внимание, что мы заменяем пробелы в коммен- тарии подчёркиваниями: управлять файлами без пробелов в именах намного легче. 13.6 Дополнительные усовершенствования Четвёртая версия – вполне удовлетворительный рабочий сценарий для большинства пользователей, однако нет пределов совершенства. Например, в программу можно доба- вить уровень подробности 8 вывода, чтобы при указании параметра « -v » она становилась более «разговорчивой». Ещё одним возможным улучшением была бы возможность передавать сценарию другие файлы и каталоги прямо в командной строке. Эти имена можно получать из списка sys. argv и добавлять к нашему списку source при помощи метода extend класса list Наиболее важным усовершенствованием было бы прекращение использования os. system для создания архивов, а применение вместо него встроенных модулей zipfile или tarfile . Они являются частью стандартной библиотеки, поэтому всегда доступны для использования без зависимости от внешней программы zip на компьютере. 8 verbosity – англ. «многословность». Применительно к компьютерным программам обозначает степень подробности выводимых программой сообщений, т.е. степень «разговорчивости» программы. Отсюда и название этого параметра (прим.перев) 13.6. Дополнительные усовершенствования 106 A Byte of Python (Russian), Версия 2.02 В приведённых примерах мы использовали способ с os.system для создания резервных копий исключительно в педагогических целях, чтобы пример был достаточно прост для понимания любым читателем, но достаточно реален для того, чтобы делать что-то полез- ное. Попробуйте написать пятую версию с использованием модуля zipfile вместо вызова os. system 13.7 Процесс разработки программного обеспече- ния В процессе создания программы мы прошли через несколько стадий. Эти стадии можно свести примерно в такой список: • Что (Анализ) • Как (Проектирование) • Создание (Реализация) • Тестирование (Тестирование и Отладка) • Использование (Развёртывание и Оперирование) • Поддержка (Усовершенствование) Процедура, которую мы прошли при написании сценария создания резервных копий ре- комендуется и для других программ: Проведите анализ и проектирование. Начните ре- ализацию с простейшей версии. Протестируйте и отладьте её. Попользуйтесь ею, чтобы убедиться, что она работает, как ожидалось. После этого добавляйте любые необходимые функции, повторяя цикл «Создание-Тестирование-Использование» столько раз, сколько потребуется. Помните, Программы выращиваются, а не строятся. 13.8 Резюме Мы увидели, как создавать свои собственные программы/сценарии на Python, а также различные стадии написания программ. На данном этапе вам будет полезно создать соб- ственную программу по такому рецепту, как мы это делали в настоящей главе, чтобы лучше привыкнуть к Python, равно как и к решению задач. Далее мы обсудим объектно-ориентированное программирование. 13.7. Процесс разработки программного обеспечения 107 Объектно-ориентированное программирование До сих пор наши программы состояли из функций, т.е. блоков выражений, которые мани- пулируют данными. Это называется процедурно-ориентированным стилем программиро- вания. Существует и другой способ организации программ: объединять данные и функ- ционал внутри некоего объекта. Это называется объектно-ориентированной парадигмой программирования. В большинстве случаев можно ограничиться процедурным програм- мированием, а при написании большой программы или если решение конкретной зада- чи того требует, можно переходить к техникам объектно-ориентированного программи- рования. Два основных аспекта объектно-ориентированного программирования – классы и объ- екты. Класс создаёт новый тип, а объекты являются экземплярами класса. Аналогично, когда мы говорим о «переменных типа int », это означает, что переменные, которые хра- нят целочисленные значения, являются экземплярами (объектами) класса int Замечание для программистов на статических языках Обратите внимание, что даже целые числа рассматриваются как объекты (класса int ), в отличие от C++ и Java (до версии 1.5), где целые числа являются примитивами. См. help(int) для более детального описания этого класса. Программисты на C# и Java 1.5 могут заметить сходство с концепцией упаковки и распаковки 1 Объекты могут хранить данные в обычных переменных, которые принадлежат объек- ту. Переменные, принадлежащие объекту или классу, называют полями. Объекты могут также обладать функционалом, т.е. иметь функции, принадлежащие классу. Такие функ- ции принято называть методами класса. Эта терминология важна, так как она помогает нам отличать независимые функции и переменные от тех, что принадлежат классу или объекту. Всё вместе (поля и методы) принято называть атрибутами класса. Поля бывают двух типов: они могут принадлежать каждому отдельному экземпляру объ- екта класса или всему классу. Они называются переменными экземпляра и перемен- ными класса соответственно. 1 boxing and unboxing 108 A Byte of Python (Russian), Версия 2.02 Класс создаётся ключевым словом class . Поля и методы класса записываются в блоке кода с отступом. 14.1 self Методы класса имеют одно отличие от обычных функций: они должны иметь дополни- тельно имя, добавляемое к началу списка параметров. Однако, при вызове метода никако- го значения этому параметру присваивать не нужно – его укажет Python. Эта переменная указывает на сам объект экземпляра класса, и по традиции она называется self 2 Хотя этому параметру можно дать любое имя, настоятельно рекомендуется использовать только имя self ; использование любого другого имени не приветствуется. Есть много до- стоинств использования стандартного имени: во-первых, любой человек, просматриваю- щий вашу программу, легко узнает его; во-вторых, некоторые специализированные Ин- тегрированные среды разработки (IDE) изначально рассчитаны на использование self Замечание для программистов на C++, Java и C# self в Python эквивалентно указателю this в C++ и ссылке this в Java и C#. Вы, должно быть, удивляетесь, как Python присваивает значение self и почему вам не нужно указывать это значение самостоятельно. Поясним это на примере. Предположим, у нас есть класс с именем MyClass и экземпляр этого класса с именем myobject . При вызове метода этого объекта, например, « myobject.method(arg1, arg2) », Python ав- томатически превращает это в « MyClass.method(myobject, arg1, arg2) » – в этом и состоит смысл self Это также означает, что если какой-либо метод не принимает аргументов, у него всё равно будет один аргумент – self 14.2 Классы Простейший класс показан в следующем примере (сохраните как simplestclass.py ). class Person : pass # Пустой блок p = Person() (p) Вывод: 2 self – англ. «сам» (прим.перев.) 14.1. self 109 A Byte of Python (Russian), Версия 2.02 $ python3 simplestclass.py <__main__.Person object at 0x019F85F0> Как это работает: Мы создаём новый класс при помощи оператора class и имени класса. За этим следует блок выражений, формирующих тело класса. В данном случае блок у нас пуст, на что указывает оператор pass Далее мы создаём объект-экземпляр класса, записывая имя класса со скобка- ми. (Мы узнаем больше о реализации в следующем разделе). Для проверки мы выясняем тип переменной, просто выводя её на экран. Так мы видим, что у нас есть экземпляр класса Person в модуле __main__ Обратите внимание, что выводится также и адрес в памяти компьютера, где хранится ваш объект. На вашем компьютере адрес будет другим, так как Python хранит объекты там, где имеется свободное место. 14.3 Методы объектов Итак, мы выяснили что классы/объекты могут иметь методы, представляющие собой функции, за исключением дополнительной переменной self . А теперь давайте рассмот- рим пример (сохраните как method.py ). class Person : def sayHi ( self ): ( 'Привет! Как дела?' ) p = Person() p sayHi() # Этот короткий пример можно также записать как Person().sayHi() Вывод: $ python3 method.py Привет! Как дела? Как это работает: Здесь мы видим self в действии. Обратите внимание, что метод sayHi не принимает параметров, но тем не менее, имеет self в определении функции. 14.3. Методы объектов 110 A Byte of Python (Russian), Версия 2.02 14.4 Метод __init__ Существует много методов, играющих специальную роль в классах Python. Сейчас мы увидим значительность метода __init__ Метод __init__ запускается, как только объект класса реализуется. Этот метод полезен для осуществления разного рода инициализации, необходимой для данного объекта. Об- ратите внимание на двойные подчёркивания в начале и в конце имени. Пример: (сохраните как oop_init.py ) class Person : def __init__ ( self , name): self name = name def say_hi ( self ): ( 'Привет! Меня зовут' , self name) p = Person( 'Swaroop' ) p say_hi() # Предыдущие 2 строки можно # Person('Swaroop').say_hi() Вывод: $ python oop_init.py Привет! Меня зовут Swaroop Как это работает: Здесь мы определяем метод __init__ так, чтобы он принимал параметр name (наряду с обычным self ). Далее мы создаём новое поле с именем name . Об- ратите внимание, что это две разные переменные, даже несмотря на то, что они обе названы name . Это не проблема, так как точка в выражении self. name обозначает, что существует нечто с именем «name», являющееся частью объекта «self», и другое name – локальная переменная. Поскольку мы в явном виде указываем, к которому имени мы обращаемся, путаницы не возникнет. Для создания нового экземпляра p класса Person мы указываем имя класса, после которого – аргументы в скобках: p = Person('Swaroop') Метод __init__ мы при этом не вызываем явным образом. В этом и заклю- чается специальная роль данного метода. После этого мы получаем возможность использовать поле self.name в наших методах, что и продемонстрировано в методе say_hi 14.4. Метод __init__ 111 A Byte of Python (Russian), Версия 2.02 14.5 Переменные класса и объекта Функциональную часть классов и объектов (т.е. методы) мы обсудили, теперь давайте ознакомимся с частью данных. Данные, т.е. поля, являются не чем иным, как обычны- ми переменными, заключёнными в пространствах имён классов и объектов. Это означа- ет, что их имена действительны только в контексте этих классов или объектов. Отсюда и название «пространство имён». Существует два типа полей: переменные класса и переменные объекта, которые разли- чаются в зависимости от того, принадлежит ли переменная классу или объекту соответ- ственно. Переменные класса разделяемы – доступ к ним могут получать все экземпляры этого клас- са. Переменная класса существует только одна, поэтому когда любой из объектов изме- няет переменную класса, это изменение отразится и во всех остальных экземплярах того же класса. Переменные объекта принадлежат каждому отдельному экземпляру класса. В этом случае у каждого объекта есть своя собственная копия поля, т.е. не разделяемая и никоим образом не связанная с другими такими же полями в других экземплярах. Это легко понять на примере (сохраните как objvar.py ): class Robot : '''Представляет робота с именем.''' # Переменная класса, содержащая количество роботов population = 0 def __init__ ( self , name): '''Инициализация данных.''' self name = name print ( '(Инициализация {0} )' format( self name)) # При создании этой личности, робот добавляется # к переменной 'population' Robot population += 1 def __del__ ( self ): '''Я умираю.''' ( ' {0} уничтожается!' format( self name)) Robot population -= 1 if Robot population == 0 : ( ' {0} был последним.' format( self name)) else : ( 'Осталось {0:d} работающих роботов.' format( \ (продолжение на следующей странице) 14.5. Переменные класса и объекта 112 A Byte of Python (Russian), Версия 2.02 (продолжение с предыдущей страницы) Robot population)) def sayHi ( self ): '''Приветствие робота. Да, они это могут.''' ( 'Приветствую! Мои хозяева называют меня {0} .' format( self name)) def howMany (): '''Выводит численность роботов.''' ( 'У нас {0:d} роботов.' format(Robot population)) howMany = staticmethod (howMany) droid1 = Robot( 'R2-D2' ) droid1 sayHi() Robot howMany() droid2 = Robot( 'C-3PO' ) droid2 sayHi() Robot howMany() ( " \nЗдесь роботы могут проделать какую-то работу.\n" ) ( "Роботы закончили свою работу. Давайте уничтожим их." ) del droid1 del droid2 Robot howMany() Вывод: $ python3 objvar.py (Инициализация R2-D2) Приветствую! Мои хозяева называют меня R2-D2. У нас 1 роботов. (Инициализация C-3PO) Приветствую! Мои хозяева называют меня C-3PO. У нас 2 роботов. Здесь роботы могут проделать какую-то работу. Роботы закончили свою работу. Давайте уничтожим их. R2-D2 уничтожается! Осталось 1 работающих роботов. (продолжение на следующей странице) 14.5. Переменные класса и объекта 113 A Byte of Python (Russian), Версия 2.02 (продолжение с предыдущей страницы) C-3PO уничтожается! C-3PO был последним. У нас 0 роботов. Как это работает: Это длинный пример, но он помогает продемонстрировать природу перемен- ных класса и объекта. Здесь population принадлежит классу Robot , и поэто- му является переменной класса. Переменная name принадлежит объекту (ей присваивается значение при помощи self ), и поэтому является переменной объекта. Таким образом, мы обращаемся к переменной класса population как Robot. population , а не self.population . К переменной же объекта name во всех методах этого объекта мы обращаемся при помощи обозначения self.name Помните об этой простой разнице между переменными класса и объекта. Так- же имейте в виду, что переменная объекта с тем же именем, что и переменная класса, сделает недоступной («спрячет») переменную класса! Метод howMany принадлежит классу, а не объекту. Это означает, что мы мо- жем определить его как classmethod или staticmethod , в зависимости от того, нужно ли нам знать, в каком классе мы находимся. Поскольку нам не нужна такая информация, мы воспользуемся staticmethod Мы могли достичь того же самого, используя декораторы : @staticmethod def howMany (): '''Выводит численность роботов.''' ( 'У нас {0:d} роботов.' format(Robot population)) Декораторы можно считать неким упрощённым способом вызова явного оператора, как мы видели в этом примере. Пронаблюдайте, как метод __init__ используется для инициализации экземпляра Robot с именем. В этом методе мы увеличиваем счётчик population на 1, так как добав- ляем ещё одного робота. Также заметьте, что значения self.name для каждого объекта свои, что указывает на природу переменных объекта. Помните, что к переменным и методам самого объекта нужно обращаться, пользуясь только self . Это называется доступом к атрибутам. В этом примере мы также наблюдали применение строк документации для классов, рав- но как и для методов. Во время выполнения мы можем обращаться к строке документации класса при помощи « Robot.__doc__ », а к строке документации метода – при помощи « Robot.sayHi.__doc__ ». Наряду с методом __init__ , существует и другой специальный метод __del__ , который 14.5. Переменные класса и объекта 114 A Byte of Python (Russian), Версия 2.02 вызывается тогда, когда объект собирается умереть, т.е. когда он больше не используется, и занимаемая им память возвращается операционной системе для другого использова- ния. В этом методе мы просто уменьшаем счётчик Robot.population на 1. Метод __del__ запускается лишь тогда, когда объект перестаёт использоваться, а поэто- му заранее неизвестно, когда именно этот момент наступит. Чтобы увидеть его в действии явно, придётся воспользоваться оператором del , что мы и сделали выше. |