Una nueva selección de consejos y programación de Python de mi feed @pythonetc.← Publicaciones anterioresEl orden de los bloques es except
importante: si varios bloques pueden atrapar una excepción, entonces el bloque superior la atrapará. Este código no funcionará según lo previsto: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
no funcionará porque IndexError
es una subclase LookupError
. Una excepción más específica siempre debe ser mayor: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 admite la asignación concurrente. Esto significa que todas las variables cambian inmediatamente después de evaluar todas las expresiones. Además, puede usar cualquier expresión que admita la asignación, y no solo las 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 no usará automáticamente la suma de números negativos en lugar de restar. Considere un ejemplo: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'
Este código no funciona:v1 = Velocity(20_000_000)
v2 = Velocity(10_000_000)
print(v1 - v2)
Divertido, pero este código funciona:v1 = Velocity(20_000_000)
v2 = Velocity(10_000_000)
print(v1 +- v2)
# 10022302 m/s
Esta parte está escrita por un usuario de Telegram. orsinium.Una función no puede ser tanto un generador como una función regular. Si se usa en el cuerpo de una función yield
, se convierte en un generador: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))
Sin embargo, una función regular puede devolver otro iterador: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)
Y esta opción puede ser útil en casos con simples generadores de expresión:def zeros(*, count: int, lazy: bool):
if lazy:
return (0 for _ in range(count))
return [0] * count
Al crear la comprensión del generador, debe usar paréntesis:>>> 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>
Sin embargo, pueden omitirse si la comprensión es el único argumento para la función:>>> list((x**x for x in range(4)))
[1, 1, 4, 27]
>>> list(x**x for x in range(4))
[1, 1, 4, 27]
Esto no es cierto para las funciones que tienen múltiples argumentos:>>> 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