Книга на вашем родном языке 6 2 Переводы 7 1 Доступные переводы переводы 7 3 Предисловие 16
Скачать 0.72 Mb.
|
12.9. Резюме 97 Решение задач Мы рассмотрели различные части языка Python, и теперь посмотрим, как все эти части ра- ботают вместе, проектируя и составляя программу, которая делает что-то полезное. Цель состоит в том, чтобы научиться писать сценарии на языке Python самостоятельно. 13.1 Задача Перед нами стоит следующая задача: Составить программу, которая создаёт резервные копии всех наших важных файлов. Хотя задача и проста, информации явно недостаточно, чтобы приступать к её решению. Необходим некоторый дополнительный анализ. Например, как мы выберем, какие фай- лы необходимо копировать? Как их хранить? Где их хранить? После надлежащего анализа мы проектируем нашу программу. Мы создаём список, опи- сывающий то, как наша программа должна работать. В данном случае я создал список того, как я себе представляю её работу. Когда вы проектируете программу, у вас может по- лучиться другой результат, поскольку каждый человек представляет себе это по-своему, так что это в порядке вещей. 1. Файлы и каталоги, которые необходимо скопировать, собираются в список. 2. Резервные копии должны храниться в основном каталоге резерва. 3. Файлы помещаются в zip-архив. 4. Именем для zip-архива служит текущая дата и время. 5. Будем использовать стандартную команду zip , имеющуюся по умолчанию в любом стандартном дистрибутиве GNU/Linux. Пользователи Windows могут установить её со страницы проекта GnuWin32 и добавить « C:\Program Files\GnuWin32\bin » к системной переменной окружения PATH, аналогично тому, как мы это делали для самой команды «python». Обратите внимание, что для этого подойдёт любая коман- да архивации, если у неё есть интерфейс командной строки, чтобы ей можно было передавать аргументы из нашего сценария. 98 A Byte of Python (Russian), Версия 2.02 13.2 Решение Как только проект программы более-менее устоялся, можно приступать к написанию ко- да, который и будет являться реализацией нашего решения. Сохраните как backup_ver1.py : import os import time # 1. Файлы и каталоги, которые необходимо скопировать, собираются в список. source = [ '"C: \\My Documents"' , 'C: \\Code' ] # Заметьте, что для имён, содержащих пробелы, необходимо использовать # двойные кавычки внутри строки. # 2. Резервные копии должны храниться в основном каталоге резерва. target_dir = 'E: \\Backup' # Подставьте ваш путь. # 3. Файлы помещаются в zip-архив. # 4. Именем для zip-архива служит текущая дата и время. target = target_dir + os sep + time strftime( '%Y%m %d %H%M%S' ) + '.zip' # 5. Используем команду "zip" для помещения файлов в zip-архив zip_command = "zip -qr {0} {1} " format(target, ' ' join(source)) # Запускаем создание резервной копии if os system(zip_command) == 0 : ( 'Резервная копия успешно создана в' , target) else : ( 'Создание резервной копии НЕ УДАЛОСЬ' ) Вывод: $ python3 backup_ver1.py Резервная копия успешно создана в E:\\Backup\\20080702185040.zip Теперь наступает стадия тестирования, когда мы проверяем, правильно ли работает наша программа. Если она работает не так, как ожидалось, нам придётся заняться её отладкой (дебагом) 1 , т.е. устранением багов (ошибок) в программе. Если приведённая выше программа у вас не заработает, допишите print(zip_command) прямо перед вызовом os.system и запустите программу. После этого скопируйте вы- 1 debug – применительно к компьютерным программам обозначает отладку (обнаружение и устранение ошибок, которые при этом принято называть «bug», т.е. «жук»). По всей видимости, это берёт своё начало с процедуры изгнания насекомых из схем больших ЭВМ, хотя само понятие «bug» в смысле маленькой неисправности встречается и в более ранней литературе, например, в записях Томаса Эдисона 1878 года. (прим. перев.) 13.2. Решение 99 A Byte of Python (Russian), Версия 2.02 веденную команду «zip_command» и вставьте её в командную строку, чтобы проверить, работает ли она корректно сама по себе. Если она не срабатывает, проверьте справку по команде «zip», чтобы выяснить, в чём может быть проблема. Если команда успешно вы- полняется, проверьте, совпадает ли ваша программа на Python в точности с программой, приведённой выше. Как это работает: Вы заметили, как мы превратили наш проект в код шаг за шагом. Мы использовали модули os и time , предварительно импортировав их. Далее мы указали файлы и каталоги для резервного копирования в списке source 2 Каталог назначения – это каталог, в котором мы сохраняем все резервные ко- пии, и он указывается в переменной target_dir . Именем zip-архива, кото- рый мы создаём, будет текущая дата и время, которые генерируются при по- мощи функции time.strftime() . У него будет расширение .zip , и хранить- ся он будет в каталоге target_dir Обратите внимание на употребление переменной os.sep – она содержит раз- делитель пути для конкретной операционной системы, т.е. он будет '/' в GNU/Linux и Unix 3 , '\\' в Windows и ':' в Mac OS. Использование os.sep вместо этих символов напрямую делает программу переносимой, и она смо- жет работать на всех этих операционных системах. Функция time.strftime() принимает в качестве аргумента формат вывода времени, например, такой, как мы указали в программе выше. Символ форма- та %Y будет замещён годом и столетием. Символ %m будет замещён месяцем в форме числа от 01 до 12 , и так далее. Полный список таких символов формата можно найти в справочнике по Python Имя конечного zip-файла мы создаём при помощи оператора, который соеди- няет строки, т.е. объединяет две строки и возвращает новую. После этого мы создаём строку zip_command , которая содержит команду, которую мы наме- рены выполнить. Проверить, работает ли эта команда, можно запустив её от- дельно в командной оболочке (терминал в GNU/Linux или командная строка DOS). Команда zip , которую мы используем, имеет некоторые параметры. Параметр « -q » используется для указания, что команда должна сработать тихо 4 . Пара- метр « -r » обозначает, что команда архивации должна работать рекурсивно 5 для каталогов, т.е. должна включать все подкаталоги и файлы. Оба парамет- ра объединены и указаны в краткой форме « -qr ». За параметрами следует 2 source – англ. «источник» (прим.перев.) 3 Под словом «Unix» здесь подразумеваются все операционные системы, построенные по принципам ОС Unix, а не только она сама по себе. Примерами таких операционных систем являются все дистрибутивы GNU/Linux, семейство ОС *BSD, Android, Solaris и т.д. (прим.перев.) 4 quietly – англ. «тихо» (прим.перев.) 5 recursive – англ. «рекурсивно» (прим.перев.) 13.2. Решение 100 A Byte of Python (Russian), Версия 2.02 имя создаваемого zip-архива, за которым указывается список файлов и ката- логов для резервного копирования. Мы превращаем список source в строку, используя уже знакомый нам метод join Затем мы, наконец, выполняем команду при помощи функции os.system , ко- торая запускает команду так, как будто она была запущена из системы, т.е. из командной оболочки. Она возвращает 0 , если команда выполнена успешно, в противном случае она возвращает код ошибки. В зависимости от вывода команды, мы печатаем соответствующее сообщение о том, успешным было создание резервных копий или нет. Вот и всё, мы создали сценарий для сохранения резервных копий наших важ- ных файлов! Замечание для пользователей Windows Вместо управляющей последовательности для обратной наклонной черты могут ис- пользоваться «сырые» 6 строки. Например, можно писать « C:\\Documents » или « r'C:\ Documents' ». Однако, не используйте « 'C:\Documents' », так как в этом случае окажет- ся, что вы пытаетесь применить неизвестную управляющую последовательность \D Теперь, когда у нас есть рабочий сценарий резервного копирования, мы можем использо- вать его для создания копий наших файлов. Пользователям GNU/Linux и Unix рекоменду- ется сделать этот программный файл исполнимым , чтобы иметь возможность запускать его в любое время из любого места. Это называется операционной фазой или развёрты- ванием программы. Программа, приведённая выше, работает корректно, но (обычно) поначалу программы не работают так, как вы того ожидаете. Проблемы могут возникать вследствие неправиль- ного проектирования программы, допущения ошибки при наборе программного кода и т.д. В таких случаях приходится возвращаться к стадии проектирования или отладки про- граммы. 13.3 Вторая версия Первая версия нашего сценария работает. Тем не менее, его можно улучшить так, чтобы было удобнее пользоваться в повседневной работе. Это называется стадией поддержки программы. Одно из улучшений, показавшееся мне полезным, – это лучший механизм именования файлов: использование времени в качестве имени файла, сохраняющегося в каталог с те- кущей датой в качестве имени, который в свою очередь, расположен в главном каталоге 6 raw – англ. «сырой», «необработанный» (прим.перев) 13.3. Вторая версия 101 A Byte of Python (Russian), Версия 2.02 для хранения резервных копий. Первое достоинство этого состоит в том, что копии хра- нятся в иерархической структуре, которой легче управлять. Второе достоинство – в том, что имена файлов намного короче. Третье достоинство состоит в том, что по именам ката- логов можно легко определить, в какие дни создавались резервные копии, так как каталог создаётся только в случае резервного копирования данных в этот день. Сохраните как backup_ver2.py : import os import time # 1. Файлы и каталоги, которые необходимо скопировать, собираются в список. source = [ '"C: \\My Documents"' , 'C: \\Code' ] # Заметьте, что для имён, содержащих пробелы, необходимо использовать # двойные кавычки внутри строки. # 2. Резервные копии должны храниться в основном каталоге резерва. target_dir = 'E: \\Backup' # Подставьте ваш путь. # 3. Файлы помещаются в zip-архив. # 4. Текущая дата служит именем подкаталога в основном каталоге today = target_dir + os sep + time strftime( '%Y%m %d ' ) # Текущее время служит именем zip-архива now = time strftime( '%H%M%S' ) # Создаём каталог, если его ещё нет if not os path exists(today): os mkdir(today) # создание каталога ( 'Каталог успешно создан' , today) # Имя zip-файла target = today + os sep + now + '.zip' # 5. Используем команду "zip" для помещения файлов в zip-архив zip_command = "zip -qr {0} {1} " format(target, ' ' join(source)) # Запускаем создание резервной копии if os system(zip_command) == 0 : ( 'Резервная копия успешно создана в' , target) else : ( 'Создание резервной копии НЕ УДАЛОСЬ' ) Вывод: $ python3 backup_ver2.py Каталог успешно создан E:\\Backup\\20080702 Резервная копия успешно создана в E:\\Backup\\20080702\\202311.zip (продолжение на следующей странице) 13.3. Вторая версия 102 A Byte of Python (Russian), Версия 2.02 (продолжение с предыдущей страницы) $ python3 backup_ver2.py Резервная копия успешно создана в E:\\Backup\\20080702\\202325.zip Как это работает: Большая часть программы осталась прежней. Разница в том, что теперь мы проверяем, существует ли каталог с именем, соответствующем текущей дате, внутри главного каталога для хранения резервных копий. Для этого мы ис- пользуем функцию os.path.exists . Если он не существует, мы создаём его функцией os.mkdir 13.4 Третья версия Вторая версия уже удобнее для работы с большим количеством резервных копий. С дру- гой стороны, когда их много, становится трудно отличить, какая копия для чего. Напри- мер, мы могли внести значительные изменения в какую-то программу или презентацию, и теперь хотим указать суть этих изменений в имени zip-архива. Этого легко можно до- стичь добавлением пользовательского комментария к имени zip-архива. Примечание: Следующая программа не работает, так что не переживайте, просто про- следуйте по ней, так как в ней содержится урок. Сохраните как backup_ver3.py import os import time # 1. Файлы и каталоги, которые необходимо скопировать, собираются в список. source = [ '"C: \\My Documents"' , 'C: \\Code' ] # Заметьте, что для имён, содержащих пробелы, необходимо использовать # двойные кавычки внутри строки. # 2. Резервные копии должны храниться в основном каталоге резерва. target_dir = 'E: \\Backup' # Подставьте ваш путь. # 3. Файлы помещаются в zip-архив. # 4. Текущая дата служит именем подкаталога в основном каталоге today = target_dir + os sep + time strftime( '%Y%m %d ' ) # Текущее время служит именем zip-архива now = time strftime( '%H%M%S' ) (продолжение на следующей странице) 13.4. Третья версия 103 A Byte of Python (Russian), Версия 2.02 (продолжение с предыдущей страницы) # Запрашиваем комментарий пользователя для имени файла comment = input ( 'Введите комментарий --> ' ) if len (comment) == 0 : # проверяем, введён ли комментарий target = today + os sep + now + '.zip' else : target = today + os sep + now + '_' + comment replace( ' ' , '_' ) + '.zip' # Создаём каталог, если его ещё нет if not os path exists(today): os mkdir(today) # создание каталога ( 'Каталог успешно создан' , today) # 5. Используем команду "zip" для помещения файлов в zip-архив zip_command = "zip -qr {0} {1} " format(target, ' ' join(source)) # Запускаем создание резервной копии if os system(zip_command) == 0 : ( 'Резервная копия успешно создана в' , target) else : ( 'Создание резервной копии НЕ УДАЛОСЬ' ) Вывод: $ python3 backup_ver3.py File "backup_ver3.py", line 25 target = today + os.sep + now + '_' + ^ SyntaxError: invalid syntax Как это (не) работает: Эта программа не работает! Python сообщает об обнаружении ошибки син- таксиса, что означает, что сценарий не удовлетворяет структуре, которую ожи- дает увидеть Python. Когда Python выдаёт сообщение об ошибке, он также ука- зывает нам на место ошибки. Так что мы начинаем отладку программы с этой строки. При внимательном рассмотрении, мы видим, что одна логическая строка бы- ла разбита на две физические строки, но мы не указали, что эти две физи- ческие строки являются частью одной. На деле же Python просто обнаружил оператор сложения ( + ) без соответствующего операнда в той же логической строке, а поэтому не знает, как продолжать. Помните, что мы можем указать, что логическая строка продолжается на следующей физической при помощи обратной наклонной черты в конце физической строки. Внесём это исправ- ление в нашу программу. Коррекция программы при обнаружении ошибок и 13.4. Третья версия 104 A Byte of Python (Russian), Версия 2.02 называется отладкой 7 13.5 Четвёртая версия Сохраните как backup_ver4.py import os import time # 1. Файлы и каталоги, которые необходимо скопировать, собираются в список. source = [ '"C: \\My Documents"' , 'C: \\Code' ] # Заметьте, что для имён, содержащих пробелы, необходимо использовать # двойные кавычки внутри строки. # 2. Резервные копии должны храниться в основном каталоге резерва. target_dir = 'E: \\Backup' # Подставьте ваш путь. # 3. Файлы помещаются в zip-архив. # 4. Текущая дата служит именем подкаталога в основном каталоге today = target_dir + os sep + time strftime( '%Y%m %d ' ) # Текущее время служит именем zip-архива now = time strftime( '%H%M%S' ) # Запрашиваем комментарий пользователя для имени файла comment = input ( 'Введите комментарий --> ' ) if len (comment) == 0 : # проверяем, введён ли комментарий target = today + os sep + now + '.zip' else : target = today + os sep + now + '_' + \ comment replace( ' ' , '_' ) + '.zip' # Создаём каталог, если его ещё нет if not os path exists(today): os mkdir(today) # создание каталога ( 'Каталог успешно создан' , today) # 5. Используем команду "zip" для помещения файлов в zip-архив zip_command = "zip -qr {0} {1} " format(target, ' ' join(source)) # Запускаем создание резервной копии if os system(zip_command) == 0 : ( 'Резервная копия успешно создана в' , target) |