
C'est une nouvelle sélection de trucs et astuces sur Python et la programmation de mon canal Telegram @pythonetc.
â
Publications précédentesasyncio
boucle
asyncio
n'a pas besoin d'ĂȘtre exĂ©cutĂ©e pour avoir des tĂąches. Vous pouvez crĂ©er et arrĂȘter des tĂąches mĂȘme si la boucle est arrĂȘtĂ©e en ce moment. Si la boucle est arrĂȘtĂ©e, certaines tĂąches peuvent rester incomplĂštes pour de bon.
import asyncio async def printer(): try: try: while True: print('*') await asyncio.sleep(1) except asyncio.CancelledError: print('x') finally: await asyncio.sleep(2) print('o')
Sortie:
* * || * x
Vous devez ĂȘtre sĂ»r d'attendre toutes les tĂąches avant d'arrĂȘter la boucle. Dans le cas contraire, certains blocs peuvent ĂȘtre
finally
ignorés et certains gestionnaires de contexte ne seront pas fermés.
Python vous permet de surcharger de nombreux opérateurs différents et l'opérateur shift en fait partie. Voici un exemple de création d'une composition de fonction à l'aide de cet opérateur. Ici, des signes en forme de flÚche indiquent la direction du flux de données:
from collections import deque from math import sqrt class Compose: def __init__(self): self._functions = deque() def __call__(self, *args, **kwargs): result = None for f in self._functions: result = f(*args, **kwargs) args = [result] kwargs = dict() return result def __rshift__(self, f): self._functions.append(f) return self def __lshift__(self, f): self._functions.appendleft(f) return self compose = Compose sqrt_abs = (compose() << sqrt << abs) sqrt_abs2 = (compose() >> abs >> sqrt) print(sqrt_abs(-4))
Vous pouvez passer des arguments à la métaclasse personnalisée à partir de la définition de classe. La notation de
class
charge les arguments de mots clés:
class Klass(Parent, arg='arg')
. Le mot clé de
metaclass
est réservé pour définir la métaclasse, mais d'autres sont libres d'utiliser.
Voici un exemple de métaclasse qui crée une classe sans l'un des attributs. Le nom de cet attribut est fourni dans l'argument
remove
:
class FilterMeta(type): def __new__(mcs, name, bases, namespace, remove=None, **kwargs): if remove is not None and remove in namespace: del namespace[remove] return super().__new__(mcs, name, bases, namespace) class A(metaclass=FilterMeta, remove='half'): def half(x): return x // 2 half_of_4 = half(4) half_of_100 = half(100) a = A() print(a.half_of_4)
Parfois, vous voulez Ă©puiser un gĂ©nĂ©rateur, mais vous ne vous souciez pas des valeurs qu'il gĂ©nĂšre. Cependant, vous vous souciez de certains effets secondaires, cela peut ĂȘtre une exception, Ă©crire dans un fichier, modifier une variable globale, etc.
La méthode pratique et largement utilisée pour ce faire est
list(gen())
. Cependant, ce code enregistre toute la valeur dans la mĂ©moire juste pour les supprimer immĂ©diatement aprĂšs. Cela peut ĂȘtre indĂ©sirable.
Si vous voulez éviter cela, vous pouvez utiliser
deque
avec la taille limitée à la place:
from collections import deque def inversed(nums): for num in nums: yield 1 / num try: deque(inversed([1, 2, 0]), maxlen=0) except ZeroDivisionError: print('E')</code> To be more semantically precise you better define your own <code>exhaust</code> function: <source lang="python"> def exhaust(iterable): for _ in iterable: pass
Imaginez que vous ayez une paire de classes qui sont un parent et un enfant, disent l'
User
et l'
Admin
. Vous disposez également d'une fonction qui prend une liste d'utilisateurs comme argument. Pouvez-vous alors fournir une liste d'administrateurs? La réponse est non: la fonction peut ajouter un autre utilisateur à la liste des administrateurs qui n'est pas valide et rompt les garanties fournies par la liste.
Cependant, vous pouvez fournir une
Sequence
d'administrateurs car la
Sequence
est en lecture seule. Le terme approprié ici est
Sequence
est covariant sur son type de membres.
Vous pouvez définir des types covariants en fournissant
covariant=True
comme argument
TypeVar
:
from typing import TypeVar, Generic T = TypeVar('T', covariant=True) class Holder(Generic[T]): def __init__(self, var: T): self._var: T = var def get(self) -> T: return self._var class User: pass class Admin(User): pass def print_user_from_holder(holder: Holder[User]) -> None: print(holder.get()) h: Holder[Admin] = Holder(Admin()) print_user_from_holder(h)
Au contraire, la fonction peut nécessiter un conteneur uniquement pour y placer des administrateurs. Ces conteneurs en écriture seule sont
contraires Ă son type de membres:
from typing import TypeVar, Generic T = TypeVar('T', contravariant=True) class Holder(Generic[T]): def __init__(self, var: T): self._var: T = var def change(self, x: T): self._var = x class User: pass class Admin(User): pass def place_admin_to_holder(holder: Holder[Admin]) -> None: holder.change(Admin()) h: Holder[User] = Holder(User()) place_admin_to_holder(h)
Les classes qui ne sont ni covariantes ni contravariantes sont appelées
invariantes .