前言及环境假设
Pycharm 2017
低版本的 Pycharm 并不支持 Type Hint, 所以这里假设是比较新的版本
Python 3.5
在现在的 Python 社区, 3 越来越成为主流, 好几个重量级的库 / 框架都不在对 2 提供支持而 3.5 是一个比较重要的版本(如果是新项目, 一般都直接 3.5/3.6), 所以本文使用 3.5
静态类型很重要
由于我并非相关专业人士, 这里姑且这样称呼吧由于 Python 是动态语言, 所以 Type Hint 与 C++/Java 那样的静态类型并不是一回事, 仅仅是 IDE 提示使用 (都已经选择了动态语言, 还要啥锤子, 凑合用吧 :)) 好在现在大部分人都会使用 IDE 编程(指: 编写生产代码 ), 所以 Type Hint 啥的, 还是可堪一用的
总之, 如果把 Java/C++ 的那种比喻成火箭大炮, 那 Type Hint 就是打火机左看右看, 用打火机都是要比钻木取火要好 :)
可能的需求
对类型的标注, 我们可能有如下几个方面的需求
一是入参按照参数类型分, 又可以分为如下几类:
基本内置类型, 如 str,int,list
基本类型组合产生的复杂类型, 如 list[int], dict[str, int]
用户自定的 class, 如 Person,Animal
函数参数, 即 callable, 比如回调参数:(value: str, index: int) => str
二是出参 (返回值) 基本和入参的分类一致, 不在赘述
下面我们来看看, 在 2 和 3 中, 如何分别实现我们上面列举的需求
Python 2 的方式: Doc String
Pycharm 对此有比较完备的支持, 基本够用, 唯一的缺点是繁琐
示例如下:
- class Person:
- def __init__(self, name, age):
- self._name = name
- self._age = age
- def get_name(self):
- return self._name
- def get_age(self):
- return self._age
- class Py2TypehintTester:
- def test1(self, a, b, c):
""" 第一种需求
基本很容易满足
- :type a: str
- :param a:
- :type b: str
- :param b:
- :type c: list
- :param c:
- :rtype: list
- :return:
- """
- return [a, b, c]
- def test2(self, a, b, c):
""" 第二种需求
也很容易满足, 只不过需要遵循 Pycharm 规定的语法, 它才能正确解析
- :type a: list[str]
- :param a:
- :type b: list[int]
- :param b:
- :type c: dict[str, int]
- :param c:
- :rtype: dict[str, str]
- :return:
- """
- for item in a:
- item.upper()
- def test3(self, p):
""" 第三种需求
也很容易满足.
不过需要对应的 class 在本 module 的空间内( 比如, 从别处 import 进来也是可以的)
- :type p: Person
- :param p:
- :return:
- """
- age = p.get_age()
- def test4(self, callback):
""" 第四种需求
会让你容易满足, 需要遵循特定写法
- :type callback: (str, int) -> str
- :param callback:
- :return:
- """s ='s'
- i = 1
- result = callback(s, i)
- print(result) # 能正确推导为 str
这种方式的优点很明显, 即: 没啥依赖, 只需要遵循规定的写法就好了
Python 3 的方式: Type Hint
这种方式是官方规定的, 与上面一种方式比起来, 基本上简洁许多, 而且也很符合直觉, 可能需要一段时间适应
示例如下:
- import typing # 需求导入这个库
- # 生成复合类型, 这段代码请无视
- FloatVector = typing.List[float]
- StrList = typing.List[str]
- MyT = typing.TypeVar('T')
- class Person:
- def __init__(self, name, age):
- self._name = name
- self._age = age
- def get_name(self):
- return self._name
- def get_age(self):
- return self._age
- class Py3TypehintTester:
- def test1(self, a: str, b: str, c: str) -> list:
""" 第一种需求
很简单, 形式比较简洁
- :param a:
- :param b:
- :param c:
- :return:
- """
- return [a, b, c]
- def test2(self, a: typing.List[str],
- b: typing.List[str],
- c: typing.Dict[str, int]) -> typing.Dict[str, str]:
""" 第二种需求
比较简单, 需要先了解 typing 这个库
- :param a:
- :param b:
- :param c:
- :return:
- """return {'str':'str1'
- }
- def test3(self, p: Person):
""" 第三种需求
比较简单
- :param p:
- :return:
- """
- print(p.get_age())
- def test4(self, callback: typing.Callable[[str, int], str]):
""" 第四种需求
稍复杂, 需要先仔细阅读下代码
不过这种需求基本出现的频率不多, 倒也不影响大局
- :param callback:
- :return:
- """s ='s'
- i = 1
- result = callback(s, i)
- print(result) # 能推导为 str
我的做法
if >= 3.5:
使用第二种, 毕竟简洁许多, 而且也没啥学习成本, 十几分钟的事
要求也比较高: 对 IDE 版本和 Python 版本均有要求
else:
使用第一种, 可以视作过渡吧, 反正兼容性是最好的, 哪个版本的 Pycharm 都能正确提示
附录
Pycharm type hint 文档: https://www.jetbrains.com/help/pycharm/type-hinting-in-pycharm.html
来源: https://juejin.im/post/5a8ed8f9f265da4e6e2bd920