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



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

Frühere Veröffentlichungen:



Zwei implizite Klassenmethoden


Um eine Klassenmethode zu erstellen, sollten Sie den Dekorator @classmethod . Diese Methode kann direkt von der Klasse aufgerufen werden, nicht von ihren Instanzen, und akzeptiert die Klasse als erstes Argument (normalerweise cls , nicht self ).

Es gibt jedoch zwei implizite Klassenmethoden im Python-Datenmodell: __new__ und __init_subclass__ . Sie funktionieren genau so, als wären sie mit @classmethod dekoriert, außer sie sind es nicht. ( __new__ erstellt neue Instanzen einer Klasse. __init_subclass__ ist ein Hook, der aufgerufen wird, wenn eine abgeleitete Klasse erstellt wird.)

 class Foo: def __new__(cls, *args, **kwargs): print(cls) return super().__new__( cls, *args, **kwargs ) Foo() # <class '__main__.Foo'> 

Asynchrone Kontextmanager


Wenn Sie möchten, dass ein Kontextmanager die Coroutine beim Eingeben oder Verlassen des Kontexts anhält, sollten Sie asynchrone Kontextmanager verwenden. Anstatt m.__enter__() und m.__exit__() Python wartet auf m.__aenter__() bzw. auf m.__aexit__() .

Asynchrone Kontextmanager sollten mit asynchroner Syntax verwendet werden:

 import asyncio class Slow: def __init__(self, delay): self._delay = delay async def __aenter__(self): await asyncio.sleep(self._delay / 2) async def __aexit__(self, *exception): await asyncio.sleep(self._delay / 2) async def main(): async with Slow(1): print('slow') loop = asyncio.get_event_loop() loop.run_until_complete(main()) 

Asynchronen Kontextmanager definieren


Seit Python 3.7 bietet asynccontextmanager den asynccontextmanager Dekorator, mit dem Sie den asynchronen Kontextmanager genauso definieren können wie den contextmanager :

 import asyncio from contextlib import asynccontextmanager @asynccontextmanager async def slow(delay): half = delay / 2 await asyncio.sleep(half) yield await asyncio.sleep(half) async def main(): async with slow(1): print('slow') loop = asyncio.get_event_loop() loop.run_until_complete(main()) 

Für ältere Versionen können Sie @asyncio_extras.async_contextmanager .

Unärer Plus-Operator


In Python gibt es keinen ++ Operator, stattdessen wird x += 1 verwendet. Selbst ++x ist jedoch immer noch eine gültige Syntax ( x++ jedoch nicht).

Der Haken ist, dass Python einen unären Plus-Operator hat und ++x tatsächlich x.__pos__().__pos__() . Wir können diese Tatsache missbrauchen und ++ als Inkrement arbeiten lassen (allerdings nicht empfohlen):

 class Number: def __init__(self, value): self._value = value def __pos__(self): return self._Incrementer(self) def inc(self): self._value += 1 def __str__(self): return str(self._value) class _Incrementer: def __init__(self, number): self._number = number def __pos__(self): self._number.inc() x = Number(4) print(x) # 4 ++x print(x) # 5 

Das Magicmock-Objekt


Mit dem MagicMock Objekt können Sie ein beliebiges Attribut abrufen oder eine beliebige Methode aufrufen. Nach diesem Zugriff wird ein neues Modell zurückgegeben. Darüber hinaus erhalten Sie dasselbe Scheinobjekt, wenn Sie auf dasselbe Attribut zugreifen (oder dieselbe Methode aufrufen):

 >>> from unittest.mock import MagicMock >>> m = MagicMock() >>> a = ma >>> b = mb >>> a is ma True >>> mx() is mx() True >>> mx() <MagicMock name='mock.x()' id='139769776427752'> 

Dies funktioniert offensichtlich mit sequentiellem Attributzugriff von jeder Tiefe. Methodenargumente werden jedoch ignoriert:

 >>> mabcd <MagicMock name='mock.abcd' id='139769776473480'> >>> mabcd <MagicMock name='mock.abcd' id='139769776473480'> >>> mx().y().z() <MagicMock name='mock.x().y().z()' id='139769776450024'> >>> mx(1).y(1).z(1) <MagicMock name='mock.x().y().z()' id='139769776450024'> 

Sobald Sie einen Wert für ein Attribut festgelegt haben, wird kein Mock mehr zurückgegeben:

 >>> mabcd = 42 >>> mabcd 42 >>> mxreturn_value.y.return_value = 13 >>> mx().y() 13 

Es funktioniert jedoch nicht mit m[1][2] . Der Grund dafür ist, dass der MagicMock von MagicMock nicht speziell behandelt wird, sondern lediglich ein Methodenaufruf:

 >>> m[1][2] = 3 >>> m[1][2] <MagicMock name='mock.__getitem__().__getitem__()' id='139769776049848'> >>> m.__getitem__.return_value.__getitem__.return_value = 50 >>> m[1][2] 50 

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


All Articles