随着 AI 的发展,凭借易学易用的语法、丰富的库和框架,Python 在机器学习、深度学习、自然语言处理和数据科学等领域有着广泛的应用。然而,对于初学者而言,对于 Python 的很多特性以及使用上依然还存在着巨大的争论。本文作者 Naren Yellavula 从中挑选了 5 个最为常见的论点,希望能通过实例演示,帮助解答刚入门的程序员们的困惑。
原文:
https://medium.com/dev-bits/does-python-really-sucks-e380711ec3e9
未经允许,禁止转载。
以下为译文:
各位开发者,大家好。今天我想提出一个新话题,用一种轻松的方式解决大家对 Python 编程语言经常提出的几个问题。最近我看到一些关于 Python 编程语言的负面看法,例如:“为什么 Python 无论是对儿童还是成年人来说,都是一门糟糕的入门编程语言?”等等。这种现象经常出现在使用其他编程语言的开发人员中。
我经常听到外界对 Python 的五个抱怨是:
缩进规则很可怕
没有强类型
速度慢
不适用于大型代码库
import 系统不可预测
我认为人们对过去三十二年(1991 至今)一直处于发展中的 Python 语言有一些误解。Python 绝对不是一种新语言,就像传统软件一样,它逐渐迭代形成了今天的样子。在本文中,我将澄清一些新程序员常见的误解,并解释为什么 Python 语言中存在这些令人惊讶的细节。
介绍
Leetcoder 建议使用 Python,因为 Python 使他们能够比 Java 或 Go 更快地编写代码。同样,研究人员和科学家选择 Python 作为他们创建现代机器学习包(例如 sci-kit、pandas)的主要语言,因为它简单易懂。如果你查阅 Python 的哲学“Python 之禅”(https://peps.python.org/pep-0020/),你可以清楚地看到其中的一个原则:
Simple is better than complex(简单胜于复杂)
但是,简单有时很容易会被误解为“无能”或“玩具般”的特性。正因为其简单性,Python 没有 Java 面向对象的细微差别,也没有 Erlang 或 C++ 所拥有的小众市场。这并不意味着 Python 无法表达强大的想法。与这种想法相反,Python 允许人们既与计算机交流,又与程序员交流。
最终结果是,人工智能领域的大多数研究论文都在用 Python 实现其算法。
Python 的语言设计受到简单选择的强烈影响。这意味着在需要做决策时,Python 更愿意选择简单的命名、轻量级的包等。
现在让我们看看行业内有关 Python 的一些抱怨以及如何通过提出一些具体的原因来澄清这些谬论。
缩进 Python 代码很可怕
如果你从其他编程语言(如 C、C++、C# 或 Java)转向 Python,首先遇到的困难就是代码缩进和缺少花括号{}。
为什么 Python 代码需要四个空格或一个制表符 TAB 来将一组语句放入一个逻辑块中?为什么他们不能像其他语言一样使用花括号{}来定义函数或逻辑条件?
这是很多新手在使用 Python 时首先关注到的事情。当他们在缩进方面犯错并尝试运行 Python 程序时,他们可能会收到解释器错误。让我们通过比较一个简单的 C 程序和它的 Python 对应程序,来可视化这一现象,这个程序用于查找整数数组中的最大元素。
1#include <stdio.h>
2
3int find_max(int arr[], int size) {
4 int max = arr[0];
5 for (int i = 1; i < size; i++) {
6 if (arr[i] > max) {
7 max = arr[i];
8 }
9 }
10 return max;
11}
12
13int main() {
14 int arr[] = {5, 10, 3, 8, 15};
15 int size = sizeof(arr) / sizeof(arr[0]);
16 int max = find_max(arr, size);
17 printf("Maximum element in the list: %d\n", max);
18 return 0;
19}
正如你在这里所看到的,我们定义了一个名为`find_max`的函数,用于找到整数数组中的最大整数。第 3-11 行定义了这个函数。第 6-8 行定义了一个 if 条件。因为这是 C 语言,你需要用花括号{}来标识给定块的范围。这一开始听起来是合理的,但你也可以注意到,尽管有 C 编译器的自然边界,第 4-10 行的缩进是为了可读性。可读性?对,就是这个。C 代码需要为编译器和人类提供提示,因此它同时使用花括号和基于空格的缩进。
现在,让我们看看 Python 对应的程序。
1def find_max(arr):
2 max = arr[0]
3 for num in arr:
4 if num > max:
5 max = num
6 return max
7
8arr = [5, 10, 3, 8, 15]
9max_num = find_max(arr)
10print("Maximum element in the list:", max_num)
这是用 Python 重写了上述的 C 程序。正如你所看到的,第 1-6 行定义了一个函数。第 4-5 行定义了`if`逻辑条件。这里的缩进(4个空格)告诉解释器,每个向右缩进到顶级构造的指令都属于该构造。与此同时,它还为程序员提供了可读性,以清楚地看到代码的边界。
一箭双雕,不是吗?Python 在这里做了一个合乎逻辑的决定,使用换行符(\n)作为函数和逻辑语句的自然边界。有人可能会争论说,难以看到长度为 100 行的缩进块。我同意。当你的函数有 100 行时,会变得混乱,但在这种情况下,你应该考虑将代码拆分成更小的函数,以提高可读性。
没有强类型
很多人强调 Python 缺乏像 C、Java 或 Go 那样的强类型。是的,Python 缺乏类型,但其他动态编程语言如 JavaScript、Ruby 或 Lua 也是如此。这是动态编程语言的特性。Python 缺乏基本类型是内在于其语言设计的。在 Python 中,一切都是对象,包括函数。要验证这个论点,你可以在 Python shell 中运行这个语句,使用任何数据类型。
1isinstance(1, object) # Returns True
你可以问,“为什么解释型语言没有强类型?”
答案是因为它们是解释型的。解释型语言一次性读取和执行程序。相比之下,编译型语言可以扫描程序以查看任何可能的类型不匹配,并在执行实际的编译二进制代码之前报告它们。在使用动态语言编写代码的最大好处是它的交互式反馈或REPL(读取-评估-打印循环)。Python 选择了这种方式,是因为动态程序以静态类型检查的代价更快地向用户提供反馈。
Python 的这种动态特性是否对项目有害?这取决于具体情况。如果一个人希望拥有一个没有单元测试的代码库,并且主要依赖编译器来捕获软件错误,那么 Python 对他们来说是一个正确的选择。在使用 Python 时,编写单元测试,执行异常处理,可以提高大型代码库的代码质量和可维护性。我们将在后面的部分中更详细地讨论这个问题。
Python 很慢
慢是一个相对的术语。对象 A 可能比对象 B 更快,但比对象 C 更慢。在进行比较时,我们应该更重视“对于给定用例的可接受性性能是什么?”而不是“Python 是否比 Java 慢?”。例如,在 I/O 绑定任务中,程序等待来自连接网络的答案,而不是计算即时答案。而且并不是所有任务都受 CPU 的限制。大多数 Web 服务器很少受 CPU 限制。Python 在多个网络系统之间作为粘合系统表现非常出色,并充分利用了其异步 I/O 功能。
如果一个人的 Python 应用程序的关键路径需要 CPU 密集型操作,他们可以将其卸载到使用性能高、低级编程语言实现的 RPC 或 HTTP API 中。
因此,说 Python 慢就像确认“地球很大”,但在什么情况下呢?地球与人类或喜马拉雅山相比,确实很大。但与太阳、木卫一或土星等其他天体相比,它很小。在构建控制平面的背景下,Python 绝对是可以接受的,但可能不适合用于实现受 CPU 限制的高性能数据库方面。因此,在大多数用例中,说“Python 慢”都不是一个公正的评价。
Python 不适用于大型代码库
这是我经常听到从其他编程语言迁移到 Python 的开发人员的观点。
对此,我得到的进一步原因包括:
没有类型
没有好的 IDE 自动提供代码建议支持
难以调试逻辑错误
上文中,我们已经讨论了“无类型”这一说法。拥有良好的单元测试肯定可以帮助维护代码,并不是避免使用大型代码库的强有力原因。
十年前,Python 的 IDE 自动补全功能可能落后于静态类型语言如 C# 或 Java。但现在不再如此。使用现代 IDE,如 PyCharm 和 VSCode,以及专用插件,我们几乎感觉不到任何差异。
由于代码中的多种原因,调试遗留企业项目中的逻辑错误是一场噩梦:
命名不当
函数违反单一职责原则(SRP)
共享全局状态
没有测试用例
模块/包臃肿
这些问题可以降低任何编程语言编写的项目的调试体验,而不仅仅是 Python。如果你不同意我的观点,试着调试一个大规模编写得很糟糕的 Go 项目。你会讨厌你的生活。
最后,鉴于行业正在向微服务或无服务器函数等更小的计算单元迈进,大型代码库将在十年左右的时间逐渐转变为多个代码库。也许这些代码库可以愉快地使用 Python。
Python 的 import 系统不可预测
Python 初学者也抱怨在 Python 中调试模块导入错误是多么令人沮丧。但大多数人在开始项目之前都不会阅读有关 Python 导入系统(https://docs.python.org/3/reference/import.html)和模块(https://docs.python.org/3/tutorial/modules.html#the-module-search-path)的文档。
Python和Java等语言的封装系统有很大的不同。Java 包是类的命名空间,而 Python 包是模块的命名空间。它们不一样。
结论
Python 像任何其他编程语言一样,不是万能解决方案。通过了解它的历史和细微之处,而不仅仅是语法,新手可以更好地欣赏 Python。
我喜欢 Python,因为与像 Java 这样的静态类型、富有细微差别的面向对象编程语言相比,它的学习曲线较浅,它在算法开发、机器学习和科学计算等许多领域都有所启发。所以回答我最初的问题:
Python 真的很糟糕吗?不,绝对不会,如果你仔细理解它的话。