Tipps und Tricks von meinem Telegramm-Kanal @pythonetc, September 2019



Es ist eine neue Auswahl von Tipps und Tricks zu Python und Programmierung von meinem Telegramm-Kanal @pythonetc.

Frühere Veröffentlichungen


asyncio Schleife muss nicht ausgeführt werden, um Aufgaben zu haben. Sie können Aufgaben erstellen und stoppen, obwohl die Schleife gerade gestoppt ist. Wenn die Schleife gestoppt wird, bleiben einige Aufgaben möglicherweise für immer unvollständig.

 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 

Ausgabe:

 * * || * x 

Sie müssen sicherstellen, dass Sie alle Aufgaben abwarten, bevor Sie die Schleife stoppen. Falls Sie dies nicht tun, werden möglicherweise einige finally Blöcke übersprungen und einige Kontextmanager nicht beendet.


Mit Python können Sie viele verschiedene Operatoren überladen, und der Shift-Operator ist einer davon. Hier ist ein Beispiel für das Erstellen einer Funktionszusammensetzung mit diesem Operator. Hier zeigen pfeilartige Zeichen die Richtung des Datenflusses:

 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 


Sie können Argumente aus der Klassendefinition an eine benutzerdefinierte Metaklasse übergeben. Die class unterstützt Schlüsselwortargumente: class Klass(Parent, arg='arg') . Das Schlüsselwort metaclass ist für das Festlegen der Metaclass reserviert, andere können jedoch kostenlos verwendet werden.

Hier ist ein Beispiel für eine Metaklasse, die eine Klasse ohne eines der Attribute erstellt. Der Name dieses Attributs wird im 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 


Manchmal möchten Sie einen Generator erschöpfen, aber die Werte, die er liefert, sind Ihnen egal. Sie kümmern sich jedoch um einige Nebenwirkungen, es kann eine Ausnahme sein, in eine Datei zu schreiben, globale Variablen zu ändern usw.

Der bequeme und weit verbreitete Weg, dies zu tun, ist list(gen()) . Dieser Code speichert jedoch den gesamten Wert im Speicher, um ihn unmittelbar danach zu verwerfen. Das kann unerwünscht sein.

Wenn Sie dies vermeiden möchten, können Sie stattdessen deque mit der begrenzten Größe verwenden:

 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 


Stellen Sie sich vor, Sie haben zwei Klassen, die Eltern und Kinder sind, z. B. User und Admin . Sie haben auch eine Funktion, die eine Liste von Benutzern als Argument verwendet. Können Sie dann eine Liste der Administratoren bereitstellen? Die Antwort lautet Nein: Die Funktion kann einen anderen Benutzer zur Liste der Administratoren hinzufügen. Dies ist ungültig und führt zu Garantien, die die Liste bietet.

Sie können jedoch eine Sequence von Administratoren bereitstellen, da die Sequence schreibgeschützt ist. Der richtige Begriff hier ist Sequence ist kovariant für seinen Mitgliedstyp.

Sie können kovariante Typen definieren, indem Sie covariant=True als TypeVar 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) 

Im Gegensatz dazu erfordert die Funktion möglicherweise nur Container, um Administratoren dort zu platzieren. Solche schreibgeschützten Container sind in Bezug auf ihren Mitgliedertyp kontravariant :

 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) 

Klassen, die weder kovariant noch kontravariant sind, werden als invariant bezeichnet .

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


All Articles