Es una nueva selección de consejos y trucos sobre Python y la programación de mi canal de Telegram @pythonetc.
←
Publicaciones anterioresSi desea iterar sobre varios iterables a la vez, puede usar la función
zip
(no tiene nada que ver con el formato de archivo ZIP):
from datetime import timedelta names = [ 'Eleven. Return and Revert', 'Wilderness', 'The Menagerie Inside', 'Evaporate', ] years = [ 2010, 2013, 2015, 2018, ] durations = [ timedelta(minutes=57, seconds=38), timedelta(minutes=48, seconds=5), timedelta(minutes=46, seconds=34), timedelta(minutes=43, seconds=25), ] print('Midas Fall LPs:') for name, year, duration in zip( names, years, durations ): print(f' * {name} ({year}) — {duration}')
Salida:
Midas Fall LPs: * Eleven. Return and Revert (2010) — 0:57:38 * Wilderness (2013) — 0:48:05 * The Menagerie Inside (2015) — 0:46:34 * Evaporate (2018) — 0:43:25
Un generador puede ser detenido. Puede llamar explícitamente a
g.close()
pero generalmente el recolector de basura lo hace por usted. Una vez que se llama
close
,
GeneratorExit
se eleva en el punto donde se detuvo la función del generador:
def gen(): try: yield 1 yield 2 finally: print('END') g = gen() print(next(g))
Mente tres cosas. Primero, no puede generar valores mientras maneja
GeneratorExit
:
def gen(): try: yield 1 finally: yield 3 g = gen() next(g) g.close()
En segundo lugar, la excepción no se genera si un generador aún no se ha iniciado, pero el generador aún se detiene:
def gen(): try: yield 1 finally: print('END') g = gen() g.close()
Tercero,
close
no hace nada si un generador ya está terminado:
def gen(): try: yield 1 yield 2 finally: print('END') g = gen() print(list(g)) print('Closing now') g.close()
Las cadenas f le permiten especificar el ancho del valor impreso, así como otros especificadores de formato:
>>> x = 42 >>> f'{x:5}+{x:15f}' ' 42+ 42.000000'
También pueden contener expresiones evaluadas que pueden ser útiles cuando el ancho es desconocido por adelantado:
def print_table(matrix): cols_width = [ max(len(str(row[col])) for row in matrix) for col in range(len(matrix[0])) ] for row in matrix: for i, cell in enumerate(row): print( f'{cell:{cols_width[i]}} ', end='' ) print() albums = [ ['Eleven. Return and Revert', 2010], ['Wilderness', 2013], ['The Menagerie Inside', 2015], ['Evaporate', 2018], ] print_table(albums)
Salida:
Eleven. Return and Revert 2010 Wilderness 2013 The Menagerie Inside 2015 Evaporate 2018
Si su clase se deriva de otra, la metaclase de su clase también debe derivarse de la metaclase de esa clase:
from collections import UserDict from abc import ABCMeta
Puede ser una buena idea obtener la metaclase de esa otra clase automáticamente:
def create_my_dict_class(parents): class MyDictMeta(*[type(c) for c in parents]): def __new__(cls, name, bases, dct): return super().__new__(cls, name, bases, dct) class MyDict(*parents, metaclass=MyDictMeta): pass MyDict = create_my_dict_class((UserDict,))
__init__
permite modificar un objeto justo después de la creación. Si desea controlar lo que se crea, debe usar
__new__
en
__new__
lugar:
from typing import Tuple, Dict from cached_property import cached_property class Numbers: _LOADED: Dict[Tuple[int, ...], 'Numbers'] = {} def __new__(cls, ints: Tuple[int, ...]): if ints not in cls._LOADED: obj = super().__new__(cls) cls._LOADED[ints] = obj return cls._LOADED[ints] def __init__(self, ints: Tuple[int, ...]): self._ints = ints @cached_property def biggest(self): print('calculating...') return max(self._ints) print(Numbers((4, 3, 5)).biggest) print(Numbers((4, 3, 5)).biggest) print(Numbers((4, 3, 6)).biggest)