内容简介:本文系掘金Python月专题文章,转载请注明来源江湖有句话:“动态类型一时爽,代码重构火葬场”被广为流传,这话一般出自静态语言拥护者口中,听起来有点耸人听闻,但也没有想象中的那么严重,Python在大型项目的应用太多了,Instagram就是最好的例子。Python作为动态语言,在定义变量、函数返回值、方法参数都不需要指定数据类型,某种程度上让代码变得无比简洁、灵活,抛开程序运行效率,但动态语言也存在不足,例如:
本文系掘金 Python 月专题文章,转载请注明来源
江湖有句话:“动态类型一时爽,代码重构火葬场”被广为流传,这话一般出自静态语言拥护者口中,听起来有点耸人听闻,但也没有想象中的那么严重,Python在大型项目的应用太多了,Instagram就是最好的例子。
Python作为动态语言,在定义变量、函数返回值、方法参数都不需要指定数据类型,某种程度上让代码变得无比简洁、灵活,抛开程序运行效率,但动态语言也存在不足,例如:
1、IDE的智能提示比较鸡肋,因为无法判断变量类型,所以IDE就不知道变量有那些属性和方法,没有智能提示对老鸟来说是非常痛苦的,举个简单例子,印象中str有个startwith方法,但正确的写法是 startswith,有个s,我不得不去查个文档。(不过个人建议初学者还是老老实实用编辑器手敲代码,以此加深记忆)
2、编译过程中,只能发现语法错误,类型不匹配的问题只有等程序真正运行了才知道。虽然可以通过单元测试来规避,但是如果在代码编写的过程中有IDE给我们指出来不是更好吗。
3、接口调用全靠文档注释说明,调用某个方法或函数,返回值和参数类型说明只能根据文档来确定。虽然我们可以要求 程序员 使用docstring或者注释来说明函数的参数类型以及返回值类型,有个问题是即使一开始你规规矩矩的写了docstring,但是代码更新之后,你的docstring可能就没有同步更新。
这些问题在大型项目,特别是多人合作的项目上显得尤为突出。代码规范、Code Review 就变得更重要了。正因为这些问题,社区对静态类型特性的引进呼声越来越强烈,所以在 Python3.5,也就是 PEP484 中有了类型提示(Type Hints)。定义函数时,可以指定函数的返回值类型、参数的类型。
以前写一个函数是这样的:
def greeting(name): return "Hello" + name >>> greeting("bob") 'Hellobob' >>> greeting(1) TypeError: must be str, not int 复制代码
当你不去看文档或者源代码的时候,你根本不知道你可以传递什么类型的值进去,而当你传入整数1时,只有等到程序运行的时候才能发现错误,如果有一种数据类型检查 工具 在程序启动前事先查一遍就可以避免程序出错。
在Python3.5中,用 Type Hint 的写法是这样的:
def greeting(name: str) -> str: return 'Hello ' + name 复制代码
上面就是静态类型的写法,多了 「: str」与 「-> str」,前者用来说明 name 的类型,后者指函数返回值的类型。这样一来,IDE像PyCharm这样的工具也能即时的发现代码的问题。
当然,除了IDE之外,我们还有更强大的静态类型检查工具,叫 mypy,这个工具也是由Python之父GUido亲自操刀实现的静态类型检查工具。
pip install mypy $ mypy test.py test.py:4: error: Argument 1 to "greeting" has incompatible type "int"; expected "str" 复制代码
有了类型提示,Python在代码调用、重构、甚至是静态分析等方面有了更好的效果,不但减轻了开发时自行进行型态检查的负担,更重要的是,由于有了型态上的提示,让过去Python整合开发工具上做不好的各种智能提示、重构等功能有了统一的参考标准。
某种意义上类型提示只是一种辅助功能,虽然我们加了数据类型提示,但是对于Python解释器来说,它会直接忽略掉类型提示信息,即时类型有误也不会阻止程序的运行。
而对于变量的类型,在PEP484中可以通过类型注释来说明,就是以注释的方式来说明变量的类型,例如:
from typing import List x = [] # type: List[Employee] y = [1, 2] # type: List[int] y.append("a") 复制代码
上面类型注释表示 x
必须是 Employee 对象组成的列表, y
必须是 int 构成的列表,整数列表 y
追加一个字符串后,我们用 mypy 来检查代码有什么问题:
mypy test.py xx.py:3: error: Name 'Employee' is not defined xx.py:5: error: Argument 1 to "append" of "list" has incompatible type "str"; expected "int" 复制代码
在 Python3.6,也就是 PEP526 的提案中,针对变量注解做了进一步优化,将类型的声明作为了语法的一部分,这样比起注释可读性更强,例如:
my_var: int # 声明为整数类型的变量 my_var = 5 # 通过类型检查 other_var: int = 'a' # 给整数类型变量赋值字符串,检查器会报错,但是解释器运行是不会有任何问题 print(other_var) 复制代码
mypy xx.py # 运行类型检查器 xx.py:3: error: Incompatible types in assignment (expression has type "str", variable has type "int") python test.py # 运行解释器 a 复制代码
类型提示虽然给了IDE智能提示、重构带来了很大的便利,而恰恰因为这些类型信息的声明,使得动态语言变得臃肿起来,例如:
T = TypeVar('T') S = TypeVar('S') class Foo(Generic[T]): def method(self, x: T, y: S) -> S: # Body 复制代码
这是一段有泛型的注解,看起来跟 Java 代码没什么区别了。而讽刺的是,Java也开始加入了动态语言的特性,例如在Java10中,就有本地变量类型推断特性,可以使用关键字 var 来定义变量,而不需要指定数据类型,意味着,静态语言也开始往动态语言特性方面发展。
public class VarTest { public static void main(String[] args) { var name = "java"; System.out.println(name); } } 复制代码
那么到底是静态语言好还是动态语言好,Java和Python各自作为静态语言和动态语言的代表,一个明显的特点就是都在互相借鉴彼此的优点,所谓天下大势,分久必合,合久必分。没有一种语言是完美的,Python灵活但可控性没那么强,更像是一位开放的家长,在语言的处理上给开发者最大的自由。毕竟 We are all consenting adults! 而反观Java,就像一位严苛的家长一样,小心翼翼地对待每个开发者,生怕你闯祸。
以上所述就是小编给大家介绍的《Python的静态类型之旅》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- python—静态类型检查
- Ruby 3 有望引入静态类型
- Ruby 3 有望引入静态类型
- Flow 静态类型检查开发环境搭建
- 编译型语言、解释型语言、静态类型语言、动态类型语言概念与区别
- 现代编程语言系列1:静态类型趋势
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。