Два приведенных выше примера использования модуля visitor были ориентированы на выполнение поиска, однако базовый класс, реализующий обход дерева каталогов, легко можно было бы расширить для реализации более специфических задач. Так, в примере 6.21 приводится сценарий, расширяющий класс FileVisitor возможностью подсчета количества строк в файлах с исходными текстами программ во всем дереве каталогов. Принцип его действия основан на вызове метода visitfile этого класса для каждого файла, найденного инструментом поиска, написанным нами выше в этой главе, но применение ООП обеспечивает более высокую гибкость и расширяемость.
Пример 6.21. PP4E\Tools\visitor_sloc.py
Подсчитывает строки во всех файлах с исходными текстами программ в дереве каталогов, указанном в командной строке, и выводит сводную информацию, сгруппированную по типам файлов (по расширениям). Реализует простейший алгоритм SLOC (source lines of code — строки исходного текста): если необходимо, добавьте пропуск пустых строк и комментариев.
import sys, pprint, os
from visitor import FileVisitor
class LinesByType(FileVisitor):
srcExts = [] # define in subclass
def __init__(self, trace=1):
FileVisitor.__init__(self, trace=trace)
self.srcLines = self.srcFiles = 0
self.extSums = {ext: dict(files=0, lines=0) for ext in self.srcExts}
def visitsource(self, fpath, ext):
if self.trace > 0: print(os.path.basename(fpath))
lines = len(open(fpath, ‘rb’).readlines())
self.srcFiles += 1
self.srcLines += lines
self.extSums[ext][‘files’] += 1
self.extSums[ext][‘lines’] += lines
def visitfile(self, filepath):
FileVisitor.visitfile(self, filepath) for ext in self.srcExts:
if filepath.endswith(ext): self.visitsource(filepath, ext) break
class PyLines(LinesByType):
srcExts = [‘.py’, ‘.pyw’] # just python files
class SourceLines(LinesByType):
srcExts = [‘.py’, ‘.pyw’, ‘.cgi’, ‘.html’, ‘.c’, ‘.cxx’, ‘.h’, ‘.i’]
if __name__ == ‘__main__’: walker = SourceLines() walker.run(sys.argv[1]) print(‘Visited %d files and %d dirs’ % (walker.fcount, walker.dcount)) print(‘-’*80)
print(‘Source files=>%d, lines=>%d’ % (walker.srcFiles, walker.srcLines)) print(‘By Types:’)
pprint.pprint(walker.extSums)
print(‘\nCheck sums:’, end=’ ‘)
print(sum(x[‘lines’] for x in walker.extSums.values()), end=’ ‘) print(sum(x[‘files’] for x in walker.extSums.values())) print(‘\nPython only walk:’)
walker = PyLines(trace=0)
walker.run(sys.argv[1])
pprint.pprint(walker.extSums)
Если запустить его как самостоятельный сценарий, в процессе обхода будут выводиться трассировочные сообщения (опущены здесь для экономии места) и в конце будет представлен отчет о количестве строк, сгруппированный по типам файлов. Выполните этот сценарий в своем дереве каталогов, чтобы увидеть, как он действует. В моем дереве каталогов содержится 907 файлов с исходными текстами, насчитывающих 48 000 строк, включая 783 файла (.py) и 34 000 строк с исходными текстами на языке Python:
C:\…\PP4E\Tools> visitor_sloc.py C:\temp\PP3E\Examples
Visited 1429 files and 186 dirs
Source files=>907, lines=>48047
By Types:
{‘.c’: {‘files’: 45, ‘lines’: 7370}, ‘.cgi’: {‘files’: 5, ‘lines’: 122}, ‘.cxx’: {‘files’: 4, ‘lines’: 2278}, ‘.h’: {‘files’: 7, ‘lines’: 297}, ‘.html’: {‘files’: 48, ‘lines’: 2830}, ‘.i’: {‘files’: 4, ‘lines’: 49},
‘.py’: {‘files’: 783, ‘lines’: 34601}, ‘.pyw’: {‘files’: 11, ‘lines’: 500}}
Check sums: 48047 907
Python only walk:
{‘.py’: {‘files’: 783, ‘lines’: 34601}, ‘.pyw’: {‘files’: 11, ‘lines’: 500}}
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011