Dicas e truques do meu canal de telegrama @pythonetc, janeiro de 2019



É uma nova seleção de dicas e truques sobre Python e programação no meu canal Telegram @pythonetc.

Publicações anteriores:



Dois métodos implícitos de classe


Para criar um método de classe, você deve usar o decorador @classmethod . Esse método pode ser chamado diretamente da classe, e não de suas instâncias, e aceita a classe como primeiro argumento (geralmente chamado cls , não self ).

No entanto, existem dois métodos de classe implícitos no modelo de dados Python: __new__ e __init_subclass__ . Eles funcionam exatamente como se fossem decorados com @classmethod exceto que não são. ( __new__ cria novas instâncias de uma classe, __init_subclass__ é um gancho chamado quando uma classe derivada é criada.)

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

Gerenciadores de contexto assíncronos


Se você deseja que um gerenciador de contexto suspenda a corotina ao entrar ou sair do contexto, use gerenciadores de contexto assíncronos. Em vez de chamar m.__enter__() e m.__exit__() Python aguarda m.__aenter__() e aguarda m.__aexit__() respectivamente.

Os gerenciadores de contexto assíncrono devem ser usados ​​com async com sintaxe:

 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()) 

Definindo o Gerenciador de Contexto Assíncrono


Desde o Python 3.7, o contextlib fornece o decorador asynccontextmanager que permite definir o gerenciador de contexto assíncrono da mesma maneira que o 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()) 

Para versões mais antigas, você pode usar @asyncio_extras.async_contextmanager .

Operador unário mais


Não há operador ++ no Python, x += 1 é usado. No entanto, mesmo ++x ainda é uma sintaxe válida (mas x++ não é).

O problema é que o Python possui um operador mais unário e ++x é na verdade x.__pos__().__pos__() . Podemos abusar desse fato e fazer com que o ++ funcione como incremento (embora não seja recomendado):

 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 

O objeto magicmock


O objeto MagicMock permite que você obtenha qualquer atributo ou chame qualquer método. Uma nova simulação será retornada após esse acesso. Além disso, você obtém o mesmo objeto simulado se acessar o mesmo atributo (ou chamar o mesmo método):

 >>> 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'> 

Obviamente, isso funcionará com acesso sequencial a atributos de qualquer profundidade. Os argumentos do método são ignorados:

 >>> 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'> 

Depois de definir um valor para qualquer atributo, ele não retorna mais simulação:

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

No entanto, ele não funciona com m[1][2] . O motivo é que o acesso ao item não é tratado especialmente pelo MagicMock , é apenas uma chamada de método:

 >>> 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/pt438776/


All Articles