欢迎大家来到IT世界,在知识的湖畔探索吧!
Python3标准库漫游之Typing.overload
Python3 >= 3.5
Python3.5开始Python把Typing作为标准库引入,低版本可以使用独立的Typing包
问题来源于一个友的提问,顺着问题我看了下Typing中overload的使用。
Python3中增加了Function Annotation的功能,翻译过来就是函数(方法)注解,具体用法就是:
def foo(name: str) -> str: return 'hello ' + name
欢迎大家来到IT世界,在知识的湖畔探索吧!
这么定义函数,可以达到静态类型的效果。如果你尝试使用foo(2) 传入一个int类型的话就会报错:
欢迎大家来到IT世界,在知识的湖畔探索吧!Traceback (most recent call last): File "t_t.py", line 4, in <module> foo(2) File "t_t.py", line 2, in foo return 'hello ' + name TypeError: must be str, not int
但这是运行时的错误,也就是代码在执行时才会发现问题。最好是我们能在写完代码时就发现是否存在问题。因此就有了类型检查工具,比如mypy这样的工具,还有很多IDE也集成了这样的检查工具。
如果用mypy检查上面的代码就会得到如下提示:
t_t.py:5: error: Argument 1 to "foo" has incompatible type "int"; expected "str"
有了Annotation的Python3显然是对Python大工程开发能力的增强,动态语言最大的弊端就是太灵活,当然这也是优点。不过对于有经验的开发来说,避免去修改函数的输入和输出是重要的设计思想。对于以往的参数,因为没有类型信息,所以我们需要在函数内部去做各种判断,来保证数据类型符合预期。
overload存在的必要
然后我们再来看overload。
overload翻译过来是“重载”的意思,Java中有这样的两个概念,重写(override)和重载(overload)。重写其实是在保证输入和输出不变的情况下重写实现逻辑。而重载则是允许修改输入和输出,即同一个方法名可以支持多种类型的输入和输出。
上面介绍了annotation能够声明类型,这样在执行时能发现错误,也能够在静态检查阶段发现错误。但是如果函数的参数确实需要多种类型呢?不能因为静态类型的声明而导致动态易用性的损失吧。
因此有两种方案:
- 一、使用typing.TypeVar
- 二、使用typing.overload
先说第一种,对于固定数量参数的方法而言,同一个参数如果打算接受多种类型,可以这么用,比方说参数可以是:int, float, str:
欢迎大家来到IT世界,在知识的湖畔探索吧!import typing T = typing.TypeVar('T', int, float, str) def foo(name: T) -> str: return 'hello ' + str(name) foo(2)
这种方案更类似于静态语言中的interface的概念,定义一个通用的父类,这样的话,你可以传递子类型过去。
再来看第二种的解决方案,也就是重载的方式。但是跟静态语言中还是很有差别。
import typing @typing.overload def foo(name: str) -> str: ... @typing.overload def foo(name: float) -> float: ... @typing.overload def foo(name: int, age: int) -> str: ... def foo(name, age=18): return 'hello ' + str(name) foo(2)
import typing @typing.overload def foo(name: str) -> str: ... @typing.overload def foo(name: float) -> float: ... @typing.overload def foo(name: int, age: int) -> str: ... def foo(name, age=18): return 'hello ' + str(name) foo(2)
通过定义多个同名函数,上面的同名函数需要通过overload装饰器装饰。可以看到被装饰的函数的输入类型和输出类型都可以更改。但是,最后的实现方法一定要通用,也就是没有类型注解。
这么用的作用是什么呢?文档中有一句话很重要:
“The @overload-decorated definitions are for the benefit of the type checker only, since they will be overwritten by the non-@overload-decorated definition, while the latter is used at runtime but should be ignored by a type checker. ”
翻译过来就是, 被overload装饰的函数仅仅是为了受益于类型检查工具,因为它们会被没有overload装饰的函数定义覆盖,尽管未被装饰的函数是用于运行时的,但是会被类型检查工具忽略。
所以,看到这应该明白了,overload仅仅是给检查工具用的。但如果静态类型检查变成工程的一部分的话,这也会避免很多问题,在写代码时也会比心里有底。
不过上面的代码仅仅用来说明typing.overload的作用。
总结
需要提醒的是,Python3.5.1版本的overload是不对外使用的,如果你在这个版本下尝试上面的代码应该会报错: Overloading is only supported in library stubs。
Annotation确实是个不错的特性,但是因此也需要引入更多的配套来保证整个环境的一致。因此就有了剩下的东西。可能后面还会有其他的东西。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/70301.html