来自我的Telegram频道@pythonetc的提示和技巧,2019年9月



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

以前的出版物


asyncio循环不必运行就可以执行任务。 即使循环现在已停止,您也可以创建和停止任务。 如果停止循环,则某些任务可能永远无法完成。

 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 

输出:

 * * || * x 

您必须确保在停止循环之前等待所有任务。 如果您不这样做,则可能会跳过某些finally块,而不会退出某些上下文管理器。


Python使您可以重载许多不同的运算符,而shift运算符就是其中之一。 这是如何使用此运算符创建函数组合的示例。 在这里,箭头状的符号表示数据流的方向:

 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 


您可以将参数从类定义传递给自定义元类。 class符号支持关键字参数: class Klass(Parent, arg='arg')metaclass关键字保留用于设置元类,但其他关键字则可以免费使用。

这是一个创建没有属性之一的类的元类示例。 该属性的名称在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 


有时您想用尽一个生成器,但是您并不关心生成的值。 不过,您确实会担心一些副作用,这可能是例外,例如写入文件,修改全局变量等。

方便且广泛使用的方法是list(gen()) 。 但是,此代码将所有值保存到内存中,只是在之后立即丢弃它们。 这可能是不希望的。

如果要避免这种情况,可以改用有限大小的deque

 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 


假设您有一对父级和子级的类,例如UserAdmin 。 您还具有一个将用户列表作为参数的函数。 您能提供一份管理员清单吗? 答案是否定的:该函数可以将另一个用户添加到无效的管理员列表中,并破坏该列表提供的保证。

但是,由于Sequence是只读的,因此您可以提供管理员Sequence 。 这里的适当术语是Sequence在其成员类型上是协变的。

您可以通过提供covariant=True作为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) 

相反,该功能可能只需要容器即可将管理员放在那里。 这样的只写容器在其成员类型上是相反的

 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) 

既不是协变也不是协变的类称为invariant

Source: https://habr.com/ru/post/zh-CN470107/


All Articles