Модуль fnmatch

modul fnmatch Законченные системные программы

Чтобы добиться такой экономии программного кода, модуль find вызывает функцию os.walk для обхода дерева каталогов и просто возвращает соответствующие имена файлов в процессе обхода. Однако в нем содержится еще одна новинка — модуль fnmatch, входящий в состав стандартной библиотеки Python, который выполняет сопоставление имен файлов с шаблоном. Этот модуль поддерживает общие операторы в строках шаблонов: * соответствует любому количеству символов, ? соответствует одному любому символу, а […] и [!…] соответствуют любым символам, перечисленным и отсутствующим в квадратных скобках, соответственно; другие символы соответствуют самим себе. В отличие от модуля re, модуль fnmatch поддерживает только самые общие операторы шаблонов командной оболочки Unix и не поддерживает полноценные регулярные выражения. Значение этого отличия мы увидим в главе 19.

Интересно отметить, что функция glob.glob тоже использует модуль fnmatch для сопоставления имен: она объединяет os.listdir и fnmatch для сопоставления имен файлов в каталоге практически так же, как наша функция find.find объединяет os.walk и fnmatch для поиска совпадений в деревьях (хотя функция os.walk, в свою очередь, использует функцию os.listdir). Одно из следствий всего этого состоит в том, что имеется возможность передавать функции find.find имя начального каталога и шаблон в виде строк байтов, если необходимо подавить декодирование имен файлов, содержащих символы Юникода, как это возможно при использовании функций os.walk и glob.glob, — в результате вы будете получать имена файлов в виде строк байтов. Подробнее о символах Юникода в именах файлов рассказывается в главе 4.

Для сравнения, вызов find.find со строкой шаблона «*» является примерным эквивалентом команды оболочки, выводящей содержимое дерева каталогов, такой как dir /B /S в DOS и Windows. Поскольку шаблону «*» соответствуют все файлы, такой вызов вернет все имена файлов, присутствующих в дереве, за один проход. Подобные команды мы легко можем выполнять в сценариях на языке Python с помощью функции os.popen, поэтому следующий фрагмент выполняет ту же самую работу, но он изначально является непереносимым и приводит к запуску параллельной программы:

>  >> import os

>  >> for line in os.popen(‘dir /B /S’): print(line, end=’’)

>  >> from PP4E.Tools.find import find

>  >> for name in find(pattern=’*’, startdir=’.’): print(name)

Данная утилита еще будет демонстрироваться далее в этой главе и в книге, включая самые, пожалуй, убедительные демонстрации в следующем разделе и в диалоге Grep, в главе 11 — в реализации текстового редактора PyEdit с графическим интерфейсом, где она будет играть центральную роль в многопоточном внешнем инструменте поиска. Модуль find был исключен из стандартной библиотеки, но это не повод забывать о нем.

Если модулю fnmatch имя файла передается в виде строки бай- <* тов, то шаблон также должен иметь тип bytes (либо оба аргу- *’Ч’ <•, мента должны иметь тип str), потому что используемый им модуль re, реализующий сопоставление с регулярными выражениями, не позволяет смешивать типы испытуемой строки и шаблона. Это требование по наследству переходит и нашей функции find.find, принимающей имя каталога и шаблон. Подробнее о модуле re рассказывается в главе 19.

Любопытно отметить, что модуль fnmatch в Python 3.1 также преобразует строку шаблона типа bytes в строку str Юникода и обратно в ходе внутренней обработки текста, используя при этом кодировку Latin-1. Этого достаточно для большинства применений, но это может вступать в противоречие с некоторыми кодировками, которые неточно отображаются в кодировку Latin-1. В таких ситуациях параметр sys. getfilesystemencoding мог бы точнее соответствовать используемой кодировке, так как он отражает ограничения, накладываемые файловой системой (как мы узнали в главе 4, параметр sys.getdefaultencoding отражает кодировку содержимого файлов, а не их имен).

Когда функции os.walk передаются аргументы типа str, она предполагает, что имена файлов следуют соглашениям для данной платформы, и не игнорирует ошибки декодирования, возбуждаемые функцией os.listdir. В утилите «grep» в примере PyEdit в главе 11 эта картина еще больше омрачается тем фактом, что строку str шаблона, полученную из графического интерфейса, необходимо кодировать в строку bytes, используя кодировку, возможно, неподходящую для некоторых файлов. За дополнительными подробностями обращайтесь к описанию функций fnmatch.py и os.py в руководстве по стандартной библиотеке Python и к их исходному программному коду. Работа с Юникодом может оказаться очень тонким делом.

Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011

Оцените статью
Секреты программирования
Добавить комментарий