我的电报频道@pythonetc的提示和技巧,2019年1月



这是我的Telegram频道@pythonetc中关于Python和编程的新技巧和窍门。

以前的出版物:



两种隐式类方法


若要创建类方法,应使用@classmethod装饰器。 可以直接从类而不是从其实例调用此方法,并且将该类作为第一个参数(通常称为cls ,而不是self )接受。

但是,Python数据模型中有两种隐式类方法: __new____init_subclass__ 。 它们的工作就像用@classmethod装饰一样,除非不是。 ( __new__创建类的新实例, __init_subclass__是在创建派生类时调用的钩子。)

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

异步上下文管理器


如果希望上下文管理器在进入或退出上下文时暂停协程,则应使用异步上下文管理器。 Python不会等待m.__aenter__() m.__enter__()m.__exit__()而是分别等待m.__aenter__()m.__aexit__()

异步上下文管理器应与以下语法一起使用:

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

定义异步上下文管理器


从Python 3.7开始, asynccontextmanager提供了asynccontextmanager装饰器,该装饰器允许您以与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()) 

对于较旧的版本,可以使用@asyncio_extras.async_contextmanager

一元加号运算符


Python中没有++运算符,而是使用x += 1 。 但是,即使++x仍然是有效的语法(但x++不是)。

问题是Python具有一元加号运算符,而++x实际上是x.__pos__().__pos__() 。 我们可以滥用这一事实,并使++以增量方式工作(尽管不建议这样做):

 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 

Magicmock对象


MagicMock对象使您可以从中获取任何属性或调用任何方法。 这样访问将返回新的模拟。 此外,如果访问相同的属性(或调用相同的方法),则会得到相同的模拟对象:

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

显然,这适用于任何深度的顺序属性访问。 但是,方法参数将被忽略:

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

为任何属性设置值后,它将不再返回模拟:

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

但是,它不适用于m[1][2] 。 原因是, MagicMock没有对项访问进行特殊处理,它只是一个方法调用:

 >>> 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/zh-CN438776/


All Articles