-
Notifications
You must be signed in to change notification settings - Fork 5
Python: трюки с генераторами Часть 3 Игры с файлами и каталогами
Dmitry Ponyatov edited this page Oct 4, 2019
·
8 revisions
У вас есть сотни логов веб-сервера, разбросанных по разным каталогам. Кроме того, некоторые журналы сжаты. Измените последнюю программу так, чтобы вы могли легко прочитать все эти журналы
foo/
access-log-012007.gz
access-log-022007.gz
access-log-032007.gz
...
access-log-012008
bar/
access-log-092007.bz2
...
access-log-022008
- Полезный способ поиска в файловой системе
from pathlib import Path
for filename in Path('/').rglob('*.py'):
print(filename)
- Угадай, что? Он использует генераторы!
>>> from pathlib import Path
>>> Path('/').rglob('*.py')
<generator object Path.rglob at 0x10e3e0b88>
>>>
- Таким образом, вы можете построить из него конвейеры обработки
- Откройте последовательность путей
import gzip, bz2
def gen_open(paths):
for path in paths:
if path.suffix == '.gz':
yield gzip.open(path, 'rt')
elif path.suffix == '.bz2':
yield bz2.open(path, 'rt')
else:
yield open(path, 'rt')
- Это интересно .... он принимает последовательность путей в качестве входных данных и выдает последовательность открытых файловых объектов
- Объединить элементы из одного или нескольких источников в одну последовательность элементов
def gen_cat(sources):
for src in sources:
for item in src:
yield item
или c новым синтаксисом yield from
def gen_cat(sources):
for src in sources:
yield from src
- Пример:
lognames = Path('/usr/www').rglob("access-log*")
logfiles = gen_open(lognames)
loglines = gen_cat(logfiles)
-
yield from
может использоваться для делегирования итерации из вложенных цикловfor/yield
def countup(stop):
n = 1
while n < stop:
yield n
n += 1
def countdown(n):
while n > 0:
yield n
n -= 1
def up_and_down(n):
yield from countup(n)
yield from countdown(n)
>>> for x in up_and_down(3):
... print(x)
...
1
2
3
2
1
>>>
- Генерация последовательности строк, содержащих заданное регулярное выражение
import re
def gen_grep(pat, lines):
patc = re.compile(pat)
return (line for line in lines if patc.search(line))
- Пример:
lognames = Path('/usr/www').rglob("access-log*")
logfiles = gen_open(lognames)
loglines = gen_cat(logfiles)
patlines = gen_grep(pat, loglines)
- Узнайте, сколько байт передано для определенного шаблона в целом каталоге журналов
pat = r"somepattern"
logdir = "/some/dir/"
filenames = Path(logdir).rglob("access-log*")
logfiles = gen_open(filenames)
loglines = gen_cat(logfiles)
patlines = gen_grep(pat,loglines)
bytecolumn = (line.rsplit(None,1)[1] for line in patlines)
bytes_sent = (int(x) for x in bytecolumn if x != '-')
print("Total", sum(bytes_sent))
- Генераторы отделяют итерацию от кода, который использует результаты итерации
- В последнем примере мы выполняем вычисление для последовательности строк
- Неважно, где и как эти строки генерируются
- Таким образом, мы можем подключить любое количество компонентов заранее, если они в конечном итоге создают последовательность строк
Python: трюки с генераторами Часть 4 Синтаксический разбор и обработка данных