Une nouvelle sélection de conseils et de programmation Python à partir de mon flux @pythonetc.
â
Collections précédentesSi vous souhaitez itérer plusieurs objets itérables à la fois, vous pouvez utiliser la fonction
zip
(cela n'a rien Ă voir avec le format de fichier 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}')
Résultat:
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
Vous pouvez arrĂȘter le gĂ©nĂ©rateur en appelant explicitement
g.close()
, mais le plus souvent, le garbage collector le fait pour vous. AprÚs avoir appelé
close
, au point oĂč la fonction de gĂ©nĂ©ration a Ă©tĂ© suspendue,
GeneratorExit
lancé:
def gen(): try: yield 1 yield 2 finally: print('END') g = gen() print(next(g))
N'oubliez pas trois aspects. Tout d'abord, vous ne pouvez pas continuer à générer des valeurs lors du traitement de
GeneratorExit
:
def gen(): try: yield 1 finally: yield 3 g = gen() next(g) g.close()
DeuxiĂšmement, si le gĂ©nĂ©rateur n'est pas dĂ©jĂ en marche, alors l'exception ne sera pas levĂ©e, mais le gĂ©nĂ©rateur passera toujours Ă l'Ă©tat "arrĂȘtĂ©":
def gen(): try: yield 1 finally: print('END') g = gen() g.close()
TroisiĂšmement,
close
ne fait rien si le générateur a déjà fini de fonctionner:
def gen(): try: yield 1 yield 2 finally: print('END') g = gen() print(list(g)) print('Closing now') g.close()
Les lignes f vous permettent de spécifier la largeur de la valeur affichée, ainsi que d'autres spécificateurs de formatage:
>>> x = 42 >>> f'{x:5}+{x:15f}' ' 42+ 42.000000'
Ils peuvent également contenir des expressions calculées, ce qui est utile lorsque la largeur n'est pas connue à l'avance:
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)
Résultat:
Eleven. Return and Revert 2010 Wilderness 2013 The Menagerie Inside 2015 Evaporate 2018
Si votre classe est dĂ©rivĂ©e d'une autre, la mĂ©taclasse de votre classe doit Ă©galement ĂȘtre dĂ©rivĂ©e de la mĂ©taclasse de cette classe:
from collections import UserDict from abc import ABCMeta
Il peut ĂȘtre conseillĂ© d'obtenir automatiquement la mĂ©taclasse de cette autre classe:
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__
vous permet de modifier un objet immédiatement aprÚs sa création. Si vous souhaitez contrÎler ce qui a été créé, utilisez
__new__
:
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)