Подборка @pythonetc, декабрь 2019

от автора

Новая подборка советов про Python и программирование из моего авторского канала @pythonetc.

Предыдущие публикации

Очевидно, что разные asyncio-задачи используют разные стеки. Можно в любой момент просмотреть их все, получив с помощью asyncio.all_tasks() все выполняемые сейчас задачи, а с помощью task.get_stack() получив стеки для всех задач.

import linecache import asyncio import random   async def producer(queue):     while True:         await queue.put(random.random())         await asyncio.sleep(0.01)  async def avg_printer(queue):     total = 0     cnt = 0     while True:         while queue.qsize():             x = await queue.get()             total += x             cnt += 1             queue.task_done()         print(total / cnt)         await asyncio.sleep(1)  async def monitor():     while True:         await asyncio.sleep(1.9)         for task in asyncio.all_tasks():             if task is not asyncio.current_task():                 f  = task.get_stack()[-1]                 last_line = linecache.getline(                     f.f_code.co_filename,                     f.f_lineno,                     f.f_globals,                 )                 print(task)                 print('\t', last_line.strip())          print()  async def main():     loop = asyncio.get_event_loop()      queue = asyncio.Queue()      loop.create_task(producer(queue))     loop.create_task(producer(queue))     loop.create_task(producer(queue))      loop.create_task(avg_printer(queue))     loop.create_task(monitor())    loop = asyncio.get_event_loop() loop.create_task(main()) loop.run_forever()

Чтобы не мучаться непосредственно с объектом стека и не использовать модуль linecache, можно вызвать task.print_stack().

С помощью метода translate из str вы можете преобразовывать или удалять символы в строке (как это делает утилита tr):

>>> 'Hello, world!'.translate({ ...     ord(','): ';', ...     ord('o'): '0', ... }) 'Hell0; w0rld!'

Единственным аргументом translate является словарь, в котором коды символов сопоставляются с символами (или кодам). Обычно такой словарь удобнее составлять с помощью статичного метода str.maketrans:

>>> 'Hello, world!'.translate(str.maketrans({ ...     ',': ';', ...     'o': '0', ... })) 'Hell0; w0rld!'

Или даже:

>>> 'Hello, world!'.translate(str.maketrans( ...     ',o', ';0' ... )) 'Hell0; w0rld!'

Третий аргумент предназначен для удаления символов:

>>> tr = str.maketrans(',o', ';0', '!') >>> tr {44: 59, 111: 48, 33: None} >>> 'Hello, world!'.translate(tr) 'Hell0; w0rld'

mypy пока что не поддерживает рекурсивные определения типов:

from typing import Optional, Dict from pathlib import Path  TreeDict = Dict[str, 'TreeDict']   def tree(path: Path) -> TreeDict:     return {         f.name: tree(f) if f.is_dir() else None         for f in path.iterdir()     }

Появится сообщение об ошибке: Cannot resolve name "TreeDict" (possible cyclic definition).

Следить за ситуацией можно здесь: https://github.com/python/mypy/issues/731

Чтобы обычная функция стала рекурсивной, ей достаточно вызвать саму себя. Но с генераторами не всё так просто: чаще всего нужно использовать yield from из рекурсивных генераторов:

from operator import itemgetter   tree = {     'imgs': {         '1.png': None,         '2.png': None,         'photos': {             'me.jpg': None         },     },     'MANIFEST': None, }   def flatten_tree(tree):     for name, children in sorted(         tree.items(),         key=itemgetter(0)     ):         yield name         if children:             yield from flatten_tree(children)   print(list(flatten_tree(tree)))

Вы можете использовать for не только с переменными, а вообще с любым выражением. Оно вычисляется при каждой итерации:

>>> log2 = {} >>> key = 1 >>> for log2[key] in range(100): ...     key *= 2 ... >>> log2[16] 4 >>> log2[1024] 10 

ссылка на оригинал статьи https://habr.com/ru/company/mailru/blog/484004/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *