什么是迭代?
typehints在
中是introduced
Python自Python 3.5。作为本引言的一部分,一个新的模块typing
是
引入了内置集合和抽象
的各种类型的引入
基础类。 Iterable
是一种在PEP中突出用于类型提示的类型,并由许多最常用的Python集合实现。由于Python 3.9,因此可以从collections.abc
导入此类型,并且可以用作一种类型以及抽象的基类。
什么时候使用迭代?
您开始使用Python中的类型提示,并一直遵循最佳实践来接受参数中最通用的类型,那么您可能一直在使用Iterable
。可以在您的代码期望实现__iter__
的任何地方使用Iterable
,换句话说,您需要通过某些类型的集合来迭代。
说您想将电子邮件发送给多个接收器:
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
返回有效的Iterable
,Mypy正确地断言没有类型错误。发生了什么?
pythonic方式,要检查集合是否为空的是使用if not <collection_name
。之所以起作用,是因为Python返回False
当__len__
返回0
。但是,Iterable
不需要实现__len__
和__bool__
。默认的真实值是True
,因此,即使您的代码完全键入安全,它也不会做您可能期望的事情。解决此问题的解决方案并不简单,但是您可以通过使用较小的通用类型(例如Collection
)来防止类似的错误,如果您想使用类型的检查器捕获这些错误,则确实需要__len__
实现。
结论
新的Python类型提示是对语言的欢迎补充,并提高可维护性,减少错误并为Python提供更好的编辑器支持。但是,由于历史设计,有细微的案例可能会导致您无法从键入安全代码的方式导致错误。如果您在python中使用Iterable
,请考虑使用Collection
。