Библиотека питониста | Python, Django, Flask
40.9K subscribers
2.68K photos
73 videos
51 files
4.26K links
Все самое полезное для питониста в одном канале.

Список наших каналов: https://t.me/proglibrary/9197

Для обратной связи: @proglibrary_feeedback_bot

По рекламе: @proglib_adv
РКН: https://gosuslugi.ru/snet/67b885cbd501cf3b2cdb5b36
Download Telegram
В Python 3.4+ вы можете использовать contextlib.suppress(), чтобы выборочно игнорировать определенные исключения:

#codeexample

import contextlib

with contextlib.suppress(FileNotFoundError):
os.remove('somefile.tmp')


# Это эквивалентно:

try:
os.remove('somefile.tmp')
exept FileNotFoundError:
pass


# Вернуть менеджер контекста, который подавляет
# любое из указанных исключений, если они встречаются
# в теле оператора with, а затем возобновляет
# выполнение с первым оператором после конца
# оператора with."
Вместо изменения оформленной функции вы можете создать другой вызываемый класс, который будет возвращать его экземпляры вместо функции:

#codeexample

lass CallableWithOrig:
def __init__(self, to_call, orig):
self._to_call = to_call
self._orig = orig

def __call__(self, *args, **kwargs):
return self._to_call(*args, **kwargs

@property
def orig(self):
if isinstance(self._orig, type(self)):
return self._orig.orig
else:
return self._orig

class SavingOrig:
def __init__(self, another_decorator):
self._another = another_decorator

def __call__(self, f):
return CallableWithOrig(self._another(f), f)

saving_orig = SavingOrig
Вы можете добавлять символы Юникода в строковый литерал не только по его номеру, но и по его имени.

#codeexample

>>> '\N{EM DASH}'
'—'
>>> '\u2014'
'—'

Он также совместим с f-строками:

>>> width = 800
>>> f'Width \N{EM DASH} {width}'
'Width — 800'
Если вы хотите, чтобы менеджер контекста приостанавливал сопрограмму при входе или выходе из контекста, вам следует использовать асинхронные менеджеры контекста. Вместо выхода m.__enter__() и m.__exit__() Python ожидает m.__aenter__() и m.__aexit__() соответственно.

#codeexample

Асинхронные контекстные менеджеры должны использоваться с асинхронным синтаксисом:

import asyncio

class Slow:
    def __init__(self, delay):
        self._delay = delay

    async def __aenter__(self):
        await asyncio.sleep(self._delay / 2)

    async def __aexit__(self, *exception):
        await asyncio.sleep(self._delay / 2)

async def main():
    async with Slow(1):
        print('slow')

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Символ '\' в обычной строке имеет особое значение. \t - символ табуляции, \r - возврат каретки и т. д.
Вы можете использовать необработанные строки, чтобы отключить это поведение. r '\ t' это просто обратная косая черта и т.

#codeexample

Вы, очевидно, не можете использовать «внутри r» ... ». Тем не менее, он может быть экранирован '\', но '\' сохраняется в строке:

>>> print(r'It\'s insane!')
It\'s insane!
Начиная с Python 3.5, на самом деле можно использовать распаковку со словарем и списком литералов.

#codeexample

In : {**{'a': 1}, 'b': 2, **{'c': 3}}
Out: {'a': 1, 'b': 2, 'c': 3}

In : [1, 2, *[3, 4]]
Out: [1, 2, 3, 4]

Для словарей эта форма даже более мощная, чем функция dict, поскольку она позволяет переопределять значения:

In : {
{'a': 1, 'b': 1}, 'a': 2, **{'b': 3}}
Out: {'a': 2, 'b': 3}
itertools.tee() создает несколько итераторов из одного. Это может быть полезно, если несколько потребителей должны читать один и тот же поток.

#codeexample

In : a, b, c = tee(iter(input, ''), 3)

In : next(a), next(c)
FIRST
Out: ('FIRST', 'FIRST')

In : next(a), next(b)
SECOND
Out: ('SECOND', 'FIRST')

In : next(a), next(b), next(c)
THIRD
Out: ('THIRD', 'SECOND', 'SECOND')

Данные, которые еще не используются итераторами, хранятся в памяти. Если некоторые из созданных итераторов еще не запущены во время завершения другого, это означает, что все сгенерированные элементы сохраняются в памяти для будущего использования. В этом случае проще и эффективнее использовать list (iter (input, '')) вместо tee.
Если вы хотите измерить время между двумя событиями, вы должны использовать time.monotonic() вместо time.time(). time.monotonic() никогда не возвращается назад, даже если системные часы обновлены

#codeexample

from contextlib import contextmanager
import time

@contextmanager
def timeit():
start = time.monotonic()
yield
print(time.monotonic() - start)

def main():
with timeit():
time.sleep(2)

main()
Проблема с вызовом repr других объектов в вашем собственном методе repr заключается в том, что вы не можете гарантировать, что ни один из других объектов не равен self, и вызов не является рекурсивным:

#codeexample

In : p = Pair(1, 2)
In : p
Out: Pair(1, 2)
In : p.right = p
In : p
Out: [...]
RecursionError: maximum recursion depth exceeded while calling a Python object

Чтобы легко решить эту проблему, вы можете использовать декоратор reprlib.recursive_repr:

@reprlib.recursive_repr()
def __repr__(self):
class_name = type(self).__name__
return f'{class_name}({self.left!r}, {self.right!r})'

Now it works:
In : p = Pair(1, 2)
In : p.right = p
In : p
Out: Pair(1, ...)
Типизация позволяет определить тип для генераторов

Вы можете дополнительно указать, какой тип получен, какой тип может быть отправлен в генератор, а какой возвращен. Генератор [int, None, bool] - это генератор, который выдает целые числа, возвращает логическое значение и не поддерживает g.send ().

#codeexample

Вот немного более сложный пример. chain_ while возвращает другие генераторы, пока один из них не выдаст что-то, что является сигналом для остановки в соответствии с функцией условия:

from typing import Generator, Callable, Iterable, TypeVar

Y = TypeVar('Y')
S = TypeVar('S')
R = TypeVar('R')

def chain_while(
iterables: Iterable[Generator[Y, S, R]],
condition: Callable[[R], bool],
) -> Generator[Y, S, None]:
for it in iterables:
result = yield from it
if not condition(result):
break

def r(x: int) -> Generator[int, None, bool]:
yield from range(x)
return x % 2 == 1

print(list(chain_while(
[
r(5),
r(4),
r(3),
],
lambda x: x is True,
)))