
Dies ist die achte Auswahl von Python-Tipps und -Programmierungen aus meinem @ pythonetc-Feed.
Vorherige Auswahl:
Zwei implizite Klassenmethoden
Um eine Klassenmethode zu erstellen, müssen Sie den 
@classmethod Dekorator verwenden. Dann kann diese Methode direkt von der Klasse und nicht von ihren Instanzen aufgerufen werden, und die Klasse wird als erstes Argument verwendet (normalerweise heißt sie 
cls , nicht 
self ).
Es gibt jedoch zwei implizite Klassenmethoden im Python-Datenmodell: 
__new__ und 
__init_subclass__ . Sie funktionieren so, als wären sie auch mit 
@classmethod dekoriert, obwohl dies nicht der Fall ist ( 
__new__ erstellt neue Instanzen der Klasse, und 
__init_subclass__ ist der Hook, der beim 
__init_subclass__ der abgeleiteten Klasse aufgerufen wird).
 class Foo: def __new__(cls, *args, **kwargs): print(cls) return super().__new__( cls, *args, **kwargs ) Foo()  
Asynchrone Kontextmanager
Wenn der Kontextmanager beim Betreten oder Verlassen des Kontexts die Coroutine anhalten soll, verwenden Sie asynchrone Manager. Anstatt 
m.__enter__() und 
m.__exit__() m.__aenter__() Python auf 
m.__aenter__() bzw. 
m.__aexit__() .
Asynchrone Kontextmanager müssen mit der 
async with 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()) 
Definieren eines asynchronen Kontextmanagers
Ab Python 3.7 bietet 
asynccontextmanager einen 
asynccontextmanager Dekorator, mit dem Sie einen asynchronen Kontextmanager auf dieselbe Weise 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()) 
In älteren Versionen der Sprache können Sie 
@asyncio_extras.async_contextmanager .
Unärer Plus-Operator
Python hat keinen 
++ Operator, stattdessen wird 
x += 1 . Gleichzeitig ist die Syntax 
++x gültig ( 
x++ jedoch nicht mehr).
Der Trick ist, dass Python einen unären Plus-Operator hat und 
++x tatsächlich 
x.__pos__().__pos__() . Dies kann missbraucht werden und 
++ wie ein Inkrement funktionieren lassen (aber ich würde dies nicht empfehlen):
 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)  
MagicMock-Objekt
Mit dem 
MagicMock Objekt können 
MagicMock ein beliebiges Attribut übernehmen und eine beliebige Methode aufrufen. Mit dieser Zugriffsmethode wird ein neuer Mock zurückgegeben. Darüber hinaus erhalten Sie dasselbe Stub-Objekt, 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'> 
Offensichtlich funktioniert dieser Code mit sequentiellem Zugriff auf Attribute in jeder Tiefe. In diesem Fall werden die Argumente der Methoden 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'> 
Und wenn Sie einen Wert für ein Attribut festlegen, gibt der Stub nicht mehr zurück:
 >>> mabcd = 42 >>> mabcd 42 >>> mxreturn_value.y.return_value = 13 >>> mx().y() 13 
Dies funktioniert jedoch nicht mit 
m[1][2] . Tatsache ist, dass 
MagicMock den Aufruf des Elements nicht verarbeitet, sondern nur einen 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