the5fire

关注Python、Django、Vim、Linux、Web开发、团队管理和互联网--Life is short, we need Python.


Python3标准库漫游之Typing.overload

作者:the5fire | 标签:       | 发布:2018-03-11 1:08 p.m. | 阅读量: 9919, 8755

Python3标准库漫游之Typing.overload

Python3 >= 3.5

Python3.5开始Python把Typing作为标准库引入,低版本可以使用独立的Typing包

问题来源于一个QQ群友的提问,顺着问题我看了下Typing中overload的使用。

Python3中增加了Function Annotation的功能,翻译过来就是函数(方法)注解,具体用法就是:

def foo(name: str) -> str:
    return 'hello ' + name

这么定义函数,可以达到静态类型的效果。如果你尝试使用foo(2) 传入一个int类型的话就会报错:

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:

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)

通过定义多个同名函数,上面的同名函数需要通过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确实是个不错的特性,但是因此也需要引入更多的配套来保证整个环境的一致。因此就有了剩下的东西。可能后面还会有其他的东西。

另外谨慎声明:本篇文章仅仅是作者在看文档和部分代码是的一些想法,仅供参考。

最后讲一个段子:某创业公司司招了个比较水的程序员,在招不到人的情况下,为了保证项目进度,于是又招了项目经理。因为当程序员较水,搞不定服务器上的配置,于是又招了个运维工程师,...
——段子来源:陈皓(coolshell)在<代码时间>的访谈。

参考

  • https://docs.python.org/3/library/typing.html
  • https://github.com/mirumee/prices
- from the5fire.com
----EOF-----

微信公众号:Python程序员杂谈


其他分类: