社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

Python3标准库漫游之Typing.overload

码农悟凡 • 8 年前 • 885 次点击  

Python3标准库漫游之Typing.overload

Python3 >= 3.5

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

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

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

  1. def foo(name: str) -> str:

  2.    return 'hello ' + name

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

  1. Traceback (most recent call last):

  2.  File "t_t.py", line 4, in

  3.    foo(2)

  4.  File "t_t.py", line 2, in foo

  5.    return 'hello ' + name

  6. TypeError: must be str, not int

但这是运行时的错误,也就是代码在执行时才会发现问题。最好是我们能在写完代码时就发现是否存在问题。因此就有了类型检查工具,比如mypy这样的工具,还有很多IDE也集成了这样的检查工具。

如果用mypy检查上面的代码就会得到如下提示:

  1. 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:

  1. import typing

  2. T = typing.TypeVar('T', int, float, str)

  3. def foo(name: T) -> str:

  4.    return 'hello ' + str(name)

  5. foo(2)

这种方案更类似于静态语言中的interface的概念,定义一个通用的父类,这样的话,你可以传递子类型过去。

再来看第二种的解决方案,也就是重载的方式。但是跟静态语言中还是很有差别。

  1. import typing

  2. @typing.overload

  3. def foo(name: str) -> str:

  4.    ...

  5. @typing.overload

  6. def foo(name: float) -> float:

  7.    ...

  8. @typing.overload

  9. def foo(name: int, age: int) -> str:

  10.    ...

  11. def foo(name, age=18):

  12.    return 'hello ' + str(name)

  13. 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


----EOF----- 

点击{原文链接}试听Django实战视频


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/rUOISvVEaE
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/8456