break
statement suppresses exception if used in the finally
clause even when the except
block is not presented:for i in range(10):
try:
1 / i
finally:
print('finally')
break
print('after try')
print('after while')
finally
after while
continue
, however it can’t be used in finally
until Python 3.8:SyntaxError: 'continue' not supported inside 'finally' clause
>>> '\N{EM DASH}'
'—'
>>> '\u2014'
'—'
>>> width = 800
>>> f'Width \N{EM DASH} {width}'
'Width — 800'
__lt__
for <
__gt__
for >
__le__
for <=
__ge__
for >=
__eq__
for ==
__ne__
for !=
NotImplemented
, the following rules applied:a.__lt__(b)
is the same as b.__gt__(a)
a.__le__(b)
is the same as b.__ge__(a)
a.__eq__(b)
is the same as not a.__ne__(b)
(mind that a
and b
are not swapped in this case)a >= b
and a != b
don’t automatically imply a > b
. The functools.total_ordering
decorator create all six methods based on __eq__
and one of the following: __lt__
, __gt__
, __le__
, or __ge__
.from functools import total_ordering
@total_ordering
class User:
def __init__(self, pk, name):
self.pk = pk
self.name = name
def __le__(self, other):
return self.pk <= other.pk
def __eq__(self, other):
return self.pk == other.pk
assert User(2, 'Vadim') < User(13, 'Catherine')
@
) and create the decorated function manually:import json
def ensure_list(f):
def decorated(*args, **kwargs):
result = f(*args, **kwargs)
if isinstance(result, list):
return result
else:
return [result]
return decorated
def load_data_orig(string):
return json.loads(string)
load_data = ensure_list(load_data_orig)
print(load_data('3')) # [3]
print(load_data_orig('4')) 4
orig
attribute of the new one:import json
def saving_orig(another_decorator):
def decorator(f):
decorated = another_decorator(f)
decorated.orig = f
return decorated
return decorator
def ensure_list(f):
...
@saving_orig(ensure_list)
def load_data(string):
return json.loads(string)
print(load_data('3')) # [3]
print(load_data.orig('4')) # 4
functools.wraps
you can use the __wrapped__
attribute to access the undecorated function:import json
from functools import wraps
def ensure_list(f):
@wraps(f)
def decorated(*args, **kwargs):
result = f(*args, **kwargs)
if isinstance(result, list):
return result
else:
return [result]
return decorated
@ensure_list
def load_data(string):
return json.loads(string)
print(load_data('3')) # [3]
print(load_data.__wrapped__('4')) # 4
__wrapped__
for each decorator applied:def ensure_list(f):
...
def ensure_ints(f):
@wraps(f)
def decorated(*args, **kwargs):
result = f(*args, **kwargs)
return [int(x) for x in result]
return decorated
@ensure_ints
@ensure_list
def load_data(string):
return json.loads(string)
for f in (
load_data,
load_data.__wrapped__,
load_data.__wrapped__.__wrapped__,
):
print(repr(f('"4"')))
[4]
['4']
'4'
@saving_orig
mentioned above accepts another decorator as an argument. What if that decorator can be parametrized? Well, since parameterized decorator is a function that returns an actual decorator, this case is handled automatically:import json
from functools import wraps
def saving_orig(another_decorator):
def decorator(f):
decorated = another_decorator(f)
decorated.orig = f
return decorated
return decorator
def ensure_ints(*, default=None):
def decorator(f):
@wraps(f)
def decorated(*args, **kwargs):
result = f(*args, **kwargs)
ints = []
for x in result:
try:
x_int = int(x)
except ValueError:
if default is None:
raise
else:
x_int = default
ints.append(x_int)
return ints
return decorated
return decorator
@saving_orig(ensure_ints(default=0))
def load_data(string):
return json.loads(string)
print(repr(load_data('["2", "3", "A"]')))
print(repr(load_data.orig('["2", "3", "A"]')))
@saving_orig
decorator doesn’t really do what we want if there are more than one decorator applied to a function. We have to call orig
for each such decorator:import json
from functools import wraps
def saving_orig(another_decorator):
def decorator(f):
decorated = another_decorator(f)
decorated.orig = f
return decorated
return decorator
def ensure_list(f):
...
def ensure_ints(*, default=None):
...
@saving_orig(ensure_ints(default=42))
@saving_orig(ensure_list)
def load_data(string):
return json.loads(string)
for f in (
load_data,
load_data.orig,
load_data.orig.orig,
):
print(repr(f('"X"')))
[42]
['X']
'X'
saving_orig
arguments:def saving_orig(*decorators):
def decorator(f):
decorated = f
for d in reversed(decorators):
decorated = d(decorated)
decorated.orig = f
return decorated
return decorator
...
@saving_orig(
ensure_ints(default=42),
ensure_list,
)
def load_data(string):
return json.loads(string)
for f in (
load_data,
load_data.orig,
):
print(repr(f('"X"')))
[42]
'X'
saving_orig
smart enough to pass orig
from one decorated function to another:def saving_orig(another_decorator):
def decorator(f):
decorated = another_decorator(f)
if hasattr(f, 'orig'):
decorated.orig = f.orig
else:
decorated.orig = f
return decorated
return decorator
@saving_orig(ensure_ints(default=42))
@saving_orig(ensure_list)
def load_data(string):
return json.loads(string)
__call__
methodclass SavingOrig:
def __init__(self, another_decorator):
self._another = another_decorator
def __call__(self, f):
decorated = self._another(f)
if hasattr(f, 'orig'):
decorated.orig = f.orig
else:
decorated.orig = f
return decorated
saving_orig = SavingOrig
class 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
К сожалению, не доступен сервер mySQL