15.01.2020       Выпуск 317 (13.01.2020 - 19.01.2020)       Статьи

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

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

Читать>>




Экспериментальная функция:

Ниже вы видите текст статьи по ссылке. По нему можно быстро понять ссылка достойна прочтения или нет

Просим обратить внимание, что текст по ссылке и здесь может не совпадать.

Новая подборка советов про 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





Разместим вашу рекламу

Пиши: mail@pythondigest.ru

Нашли опечатку?

Выделите фрагмент и отправьте нажатием Ctrl+Enter.

Система Orphus