В Python 3.4+ вы можете использовать
#codeexample
# Это эквивалентно:
# Вернуть менеджер контекста, который подавляет
# любое из указанных исключений, если они встречаются
# в теле оператора with, а затем возобновляет
# выполнение с первым оператором после конца
# оператора with."
contextlib.suppress()
, чтобы выборочно игнорировать определенные исключения:#codeexample
import contextlib
with contextlib.suppress(FileNotFoundError):
os.remove('somefile.tmp')
# Это эквивалентно:
try:
os.remove('somefile.tmp')
exept FileNotFoundError:
pass
# Вернуть менеджер контекста, который подавляет
# любое из указанных исключений, если они встречаются
# в теле оператора with, а затем возобновляет
# выполнение с первым оператором после конца
# оператора with."
Вместо изменения оформленной функции вы можете создать другой вызываемый класс, который будет возвращать его экземпляры вместо функции:
#codeexample
#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'
#codeexample
>>> '\N{EM DASH}'
'—'
>>> '\u2014'
'—'
Он также совместим с f-строками:
>>> width = 800
>>> f'Width \N{EM DASH} {width}'
'Width — 800'
Если вы хотите, чтобы менеджер контекста приостанавливал сопрограмму при входе или выходе из контекста, вам следует использовать асинхронные менеджеры контекста. Вместо выхода
#codeexample
Асинхронные контекстные менеджеры должны использоваться с асинхронным синтаксисом:
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!
Вы можете использовать необработанные строки, чтобы отключить это поведение. 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}
#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.
#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()
#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, ...)
#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,
)))
Вы можете дополнительно указать, какой тип получен, какой тип может быть отправлен в генератор, а какой возвращен. Генератор [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,
)))