Trucs et astuces de ma chaĂźne Telegram @pythonetc, septembre 2019



C'est une nouvelle sélection de trucs et astuces sur Python et la programmation de mon canal Telegram @pythonetc.

← Publications prĂ©cĂ©dentes


asyncio 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') # never happens loop = asyncio.get_event_loop() run = loop.run_until_complete task = loop.create_task(printer()) run(asyncio.sleep(1)) # printer works here print('||') run(asyncio.sleep(1)) # printer works here task.cancel() # nothing happens run(asyncio.sleep(1)) # x printed 

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)) # 2.0 print(sqrt_abs2(-4)) # 2.0 


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) # 2 print(a.half_of_100) # 50 a.half # AttributeError 


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 .

Source: https://habr.com/ru/post/fr470107/


All Articles