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

电报频道

It is a new selection of tips and tricks about Python and programming from my Telegram-channel @pythonetc.

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

Previous publications

以前的出版物

asyncio loop doesn’t have to be run to have tasks. You can create and stop tasks even though the loop is stopped right now. If loop is stopped, some tasks may stay incompleted for good. 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

Output:

输出:

*
*
||
*
x

You have to be sure to await all tasks before stopping the loop. In case you don’t you may have some finally blocks being skipped and some context managers not being exited.

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

Python lets you overload many different operators and the shift operator is one of them. Here is an example of how to create a function composition using this operator. Here, arrow-like signs show the data-flow direction:

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

You can pass arguments to custom metaclass from the class definition. The class notation support keyword arguments: class Klass(Parent, arg='arg'). The metaclass keyword is reserved for setting metaclass, but others are free to use.

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

Here is an example of metaclass that creates class without one of the attributes. The name of that attribute is provided in the remove argument:

这是一个创建不带任何属性的类的元类示例。 该属性的名称在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

Sometimes you want to exhaust a generator, but you don’t care about the values it yields. You do care about some side effect though, it may be an exception, writing to a file, global variable modification etc.

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

The convenient and widely used way to do this is list(gen()). However, this code saves all the value into the memory just to discard them immediately after. That can be undesirable.

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

If you want to avoid this you can use deque with the limited size instead:

如果要避免这种情况,可以改用有限大小的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

Imagine you have a pair of classes that are a parent and a child, say User and Admin. You also have a function that takes a list of users as an argument. Can you provide a list of admins then? The answer is no: the function can add another user to the list of admins which is invalid and breaks guarantees that the list provides.

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

However, you can provide a Sequence of admins since Sequence is read-only. The proper term here is Sequence is covariant on its members type.

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

You can define covariant types by providing covariant=True as a TypeVar argument:

您可以通过提供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)

Contrariwise, the function may require container only to put admins there. Such write-only containers are contravariant on its members type:

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

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)

Classes that are neither covariant nor contravariant are called invariant.

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

翻译自: https://habr.com/en/company/mailru/blog/470107/

电报频道

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值