Python 中的可迭代陷阱


什么是可迭代对象?

Typehints从Python 3.5开始Python中
引入。作为此介绍的一部分,引入了
一个新模块,其中包含内置集合和抽象
基础 Classes.is 的各种类型,该类型在 PEP 中突出显示用于类型提示,并由许多最常用的 Python 集合实现。从 Python 3.9 开始,此类型可以从中导入并可用作类型和抽象基类。
typingIterablecollections.abc

何时使用可迭代对象?

如果您开始在 Python 中使用类型提示,并且一直遵循最佳实践来接受参数中可能的最通用类型,那么您可能一直在使用 .can 在您的代码期望变量实现的任何地方使用,换句话说,您的代码想要遍历某种集合的地方。IterableIterable__iter__

假设您要向多个收件人发送电子邮件:

class MailApi:
    def sendmail(self, sender: str, receiver: str, message: str) -> None:
        ...


api = MailApi()


def send_emails(message: str, sender: str, receivers: Iterable[str]) -> Optional[T]:
    if not receivers:
        raise ValueError("you need atleast one receiver")

    for receiver in receivers:
        api.sendmail(sender, receiver, message)

如果您使用以下代码发送电子邮件,您将发送电子邮件:

send_emails(
    "Hello",
    "me@example.com",
    ["steve@example.com", "larry@example.com", "elon@example.com"],
)

如果使用以下代码,将出现异常:

send_emails("Hello", "me@example.com", [])

陷阱

但是,如果您这样做呢?

send_emails(
    "Hello",
    "me@example.com",
    filter(
        lambda x: not x.endswith("example.com"),
        ["steve@example.com", "larry@example.com", "elon@example.com"],
    ),
)

您会直观地期望出现异常,因为过滤器将删除所有匹配的电子邮件,但什么都不会发生!

filter返回一个 validand MyPy 正确断言没有类型错误。这是怎么回事?Iterable

pythonic 的方法是检查集合是否为空。这是有效的,因为 Python 返回时返回。但是,不需要实施以及。默认的真值为 ,因此即使您的代码完全是类型安全的,它也不会执行您可能期望的操作。此问题的解决方案并不简单,但是如果要使用类型检查器捕获这些错误,则可以通过使用稍微不那么泛型的类型来防止类似的错误,例如,这确实需要实现。if not <collection_nameFalse__len__0Iterable__len____bool__TrueCollection__len__

结论

新的 Python 类型提示是该语言的一个受欢迎的补充,提高了可维护性,减少了错误,并允许对 Python 提供更好的编辑器支持。但是,由于历史设计决定,有一些微妙的情况可能会导致错误,其方式是你对类型安全代码所不期望的。如果你在 Python 中使用,请考虑使用。

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/292681.html

(0)
上一篇 2022年11月7日
下一篇 2022年11月7日

相关推荐

发表回复

登录后才能评论