时间:2022-08-04 21:40来源:财神爷站
不少人认为?Python?方便掌握,而且不易出错。然而,并非所有人都同意这个观点。
许多高级开发表示,使用动态类型的语言实在很令人头疼:
“什么?动态类型的语言比静态类型的语言更加不容易出错?抱歉,21年的软件开发职业生涯告诉我并不是这样。”
——?Rasmus?Schultz
在本文中,我们就来看一看高级开发人员不喜欢动态类型语言的主要原因,同时我也希望通过本文消除大家的误解。
为了更好地挖掘背后的原因,以及鉴于?Python?的广泛普及,我们以?Python?为例来分析一下。
动态类型
这里所说的动态类型指的是数据类型。
编程语言包含多种类型的风格,比如强类型和鸭子类型等。但是,在本文中我们只讨论两个最常见的类型:
动态类型
静态类型
动态类型指的是在运行时检查类型错误。也就是说不需要显式声明数据类型。Python、Ruby?和?Java?都是这类语言。
与动态类型相反,静态类型则会在编译期间报告类型错误,因此你需要显式声明数据类型。C、C++?和?Java?就属于这种情况。
一般来说,Python?以及其他编程语言的某些优点也会成为缺点。
动态类型可以通过隐式的数据类型声明减少一部分代码,从而让编程变得更容易。但是,这个特性也有一些缺陷。
请考虑如下?Python?代码:
max_number?=?12?my_list?=?[]?for?i?in?range(1,?5):?max_numbre?=?2?*?(max_number?*?i)?my_list.append(max_number)
print(my_list)输出结果:[12,?12,?12,?12]
在这个例子中,我们希望针对变量?max_number?进行一些计算,并将结果存储在列表中。但是,我们可以看到实际的操作并不符合我们的预期,而结果也是错误的。因为在?for?循环中,max_number?的拼写有误,因此导致程序创建了另一个名为?max_numbre?的变量。
任何人都可能犯这样的错误,特别是对于工作压力很大的人。
假设你正在编写一大段代码,那么你必须更加小心手指按下的每一个按键。否则,查找代码中的bug就会成为噩梦,并引发维护性的问题。
然而,在静态类型的语言(比如C++)中,你必须在使用前声明变量。而且你必须在执行代码前进行分析,以确保变量类型匹配。这样你对变量的控制会更有力,因此可以提高安全性。
全局解释器锁
高级开发人员对动态类型语言的另一个质疑是性能。
初级开发人员只需要处理好几行代码,而维护和编写健壮的生产代码(几百行~几千行)的重任一般都由经验丰富的高级开发人员承担。因此,对他们来说,编程语言的效率不容置疑。
由于全局解释器锁(Global?Interpreter?Lock,即?GIL)的存在,计算机的资源(主要是?CPU?线程数)得不到充分利用,因此它是编程语言(如?Python?和?MRI?Ruby?等)的性能瓶颈。
不过,不使用?GIL?的编程语言可以充分利用?CPU?的功能,因为它们支持并行计算。
并行计算只不过是让所有线程同时运行而已。在需要处理的数据量十分庞大时,这种类型的计算会比较有优势。
下图是一个并行计算的示例:
图:所有?CPU?一起运行的示例
我们可以假设,在相同的?CPU?时钟速度下,计算机拥有的线程越多,程序的运行速度就越快。
然而,GIL?的出现终结了并行计算。
GIL?的作用是保证一次只有一个线程使用?GIL。线程的选择遵循排队方式。这意味着,当拥有最高优先级的线程正在使用?GIL?时,其他线程将处于等待状态,直到?GIL?被释放。
最重要的是,用户无法控制线程的选择。只能由操作系统负责线程优先级的排序,如下图所示:
为了解决这个问题,许多程序员都尝试手动在多个线程之间拆分进程,比如?Python?的?multithreading?模块,就是为了获得更好的性能。然而,最终的结果却是性能更差了。
这个结果有点奇怪,如果你想搞清楚事情的始末,则必须再深入研究一下。
尽管?Python?的核心开发团队已经意识到了这个问题,但是想摆脱?GIL?太难了,因为它是许多?Python?功能的基础,例如内存管理和C扩展等等。
Python?的作者?Guido?van?Rossum?表示,他不确定?Python?是否会支持并行计算,因为这归根结底是语言设计层面的问题。
但是,C++?等静态类型语言不受?GIL?的限制,因此它们的效率相对更高。
空白的敏感度
错误地使用空白就会报错,并不是每个人都喜欢这样的编程语言。空白不仅包括空格,还包括制表符、换行、返回或换页等。例如,与C不同,Python?对空格就非常敏感。
下面,我们就来比较一下?C?和?Python?代码。
Python?示例:
i?=?50ifi?%?2?==?0:?print(?"inside?if?statement")?print(?"i?is?even")?输出结果:print(?"inside?if?statement")?print(?"i?is?even")?^SyntaxError:?invalid?syntax
C?示例:
#?include intmain(?void)?{?inti?=?50;?if(i?%?2==?0)?输出结果:~/?$?./test1inside?ifstatement?i?is?even
C?的代码结构无论再怎么混乱,都可以得到正确的输出,而?Python?生成的语法错误只是因为语句的书写位置有误。因此,有人可能会说?Python?的健壮性不如?C++?或?C。
尽管许多专业程序员都认为空白过于敏感很讨人厌,但许多?Python?专家则认为,空白的问题总好过代码长得看不到尽头。
最后,在处理大块代码时,空白的敏感性问题确实很烦人。但是,如果能够向团队灌输良好的编码习惯,则这个问题也很好解决。
向后兼容
不支持向后兼容意味着旧版的?Python?代码无法在新版本中正常工作。换句话说,每当新版本发布时,你都需要找出语法的变化,并重写相应的部分代码。
有时,向后兼容性会成为一个严重的问题,Python?2?到?Python?3?就是一个很好的例子。
Python?核心开发团队认为,将?Python?2?的代码转换成?Python?3?不会有任何问题。但是他们错了。
Python?的作者也承认了这一点:
“我们低估了有多少人已经编写了大量的?Python?代码,而且他们已经基本忘记了代码的工作方式。因此,他们没能很好地升级这些代码。我们已经意识到了这个问题。”
这个问题争论到最后,他们决定延长?Python?2.7?的寿命。
总结
编程语言一直是一个热门话题,这不是一个非黑即白的两极分化问题。我们会因为某些原因而偏爱某一种编程语言。
通常,每种通用编程语言都有特定的适合人群。Python?的官方作者曾说:
“学习使用?Python?编程比学习使用?Java?或?Swift?要容易得多。Java?和?Swift?非常适合计算机科学的专业软件开发人员。但是?Python?更适合孩子的教学。”
话虽如此,我们非常希望能够出现一种兼具C++?和?Python?优点的编程语言。