Une nouvelle sélection de conseils et de programmation Python à partir de mon flux @pythonetc.← Publications précédentesL'ordre des blocs est except
important: si une exception peut être interceptée par plusieurs blocs, le bloc supérieur la rattrapera. Ce code ne fonctionnera pas comme prévu:import logging
def get(storage, key, default):
try:
return storage[key]
except LookupError:
return default
except IndexError:
return get(storage, 0, default)
except TypeError:
logging.exception('unsupported key')
return default
print(get([1], 0, 42))
print(get([1], 10, 42))
print(get([1], 'x', 42))
except IndexError
ne fonctionnera pas car il IndexError
s'agit d'une sous-classe LookupError
. Une exception plus spécifique doit toujours être plus élevée:import logging
def get(storage, key, default):
try:
return storage[key]
except IndexError:
return get(storage, 0, default)
except LookupError:
return default
except TypeError:
logging.exception('unsupported key')
return default
print(get([1], 0, 42))
print(get([1], 10, 42))
print(get([1], 'x', 42))
Python prend en charge l'affectation simultanée. Cela signifie que toutes les variables changent immédiatement après avoir évalué toutes les expressions. De plus, vous pouvez utiliser n'importe quelle expression qui prend en charge l'affectation, et pas seulement les variables:def shift_inplace(lst, k):
size = len(lst)
lst[k:], lst[0:k] = lst[0:-k], lst[-k:]
lst = list(range(10))
shift_inplace(lst, -3)
print(lst)
shift_inplace(lst, 5)
print(lst)
Python n'utilisera pas automatiquement l'addition de nombres négatifs au lieu de soustraire. Prenons un exemple:class Velocity:
SPEED_OF_LIGHT = 299_792_458
def __init__(self, amount):
self.amount = amount
def __add__(self, other):
return type(self)(
(self.amount + other.amount) /
(
1 +
self.amount * other.amount /
self.SPEED_OF_LIGHT ** 2
)
)
def __neg__(self):
return type(self)(-self.amount)
def __str__(self):
amount = int(self.amount)
return f'{amount} m/s'
Ce code ne fonctionne pas:v1 = Velocity(20_000_000)
v2 = Velocity(10_000_000)
print(v1 - v2)
C'est drôle, mais ce code fonctionne:v1 = Velocity(20_000_000)
v2 = Velocity(10_000_000)
print(v1 +- v2)
# 10022302 m/s
Cette partie est écrite par un utilisateur de Telegram. orsinium.Une fonction ne peut pas être à la fois un générateur et une fonction régulière. S'il est utilisé dans le corps d'une fonction yield
, il se transforme en générateur:def zeros(*, count: int, lazy: bool):
if lazy:
for _ in range(count):
yield 0
else:
return [0] * count
zeros(count=10, lazy=True)
zeros(count=10, lazy=False)
list(zeros(count=10, lazy=False))
Cependant, une fonction régulière peut renvoyer un autre itérateur:def _lazy_zeros(*, count: int):
for _ in range(count):
yield 0
def zeros(*, count: int, lazy: bool):
if lazy:
return _lazy_zeros(count=count)
return [0] * count
zeros(count=10, lazy=True)
zeros(count=10, lazy=False)
Et cette option peut être utile dans les cas avec de simples générateurs d'expressions:def zeros(*, count: int, lazy: bool):
if lazy:
return (0 for _ in range(count))
return [0] * count
Lors de la création de la compréhension du générateur, vous devez utiliser des parenthèses:>>> g = x**x for x in range(10)
File "<stdin>", line 1
g = x**x for x in range(10)
^
SyntaxError: invalid syntax
>>> g = (x**x for x in range(10))
>>> g
<generator object <genexpr> at 0x7f90ed650258>
Cependant, ils peuvent être omis si la compréhension est le seul argument de la fonction:>>> list((x**x for x in range(4)))
[1, 1, 4, 27]
>>> list(x**x for x in range(4))
[1, 1, 4, 27]
Cela n'est pas vrai pour les fonctions qui ont plusieurs arguments:>>> print((x**x for x in range(4)), end='\n')
<generator object <genexpr> at 0x7f90ed650468>
>>>
>>>
>>> print(x**x for x in range(4), end='\n')
File "<stdin>", line 1
SyntaxError: Generator expression must be parenthesized if not sole argument