老实说,我用 Python 开启了自己的编程之旅,因为我已经厌倦了在用 C 和 C++编写软
件时的各种困境。事实上,我们常常看到,程序员开始学习 Python,是在他们意识到其他
语言不能满足用户需求的时候。与 C,C++或 Java 相比,使用 Python 编程,是一件轻而易
举的事情。一切似乎都是如此简并且经过良好的设计。你可能会觉得再也没有地方可以犯
错误,也不再需要其他的编程语言了。
上面这种看法是完全错误的。是的,Python 是一个令人兴奋的语言,它有很多很酷的
功能,它可以用于很多领域。但这并不意味着它是完美的,也没有任何缺点。它的可读性
很好,也容易写,然而易用性也伴随着一些代价。它不会是许多人想象中的那么慢,但永
远不会像 C 一样快。它有很高的可移植性,但它的解释器无法运行在许多架构的用于其他
语言的编译器上。我们可能永远用不到这些编译器。
解决这个问题的方案之一就是是编写扩展,所以我们可以把 C 中的一些优点带到 Python 中
来。在大多数情况下,它可以工作得很好。问题是:我们使用 Python,仅仅是因为我们想用 C
扩展它吗?答案是否定的。我们在没有任何更好的选择情况,这确实是一个不太方便的解决方案。
额外的复杂性
显而易见,使用不同语言的开发应用程序不是一件容易的事情。Python 和 C 是完全不
同的技术,很难找到他们有什么共同点。不存在没有 bug 的应用程序,这也是事实。如果
扩展在代码库中变得常见,调试可能会很痛苦。不仅因为 C 代码的调试需要完全不同的工
作流程和工具,而且还需要经常在两种不同语言之间切换上下文。
我们都是人类,并且都具有有限的认知能力。当然,有人能够同时有效地处理多层抽
象和技术栈,但这种人很少见。无论你有多么熟练,对于维护这样的混合解决方案总是有
额外的代价。这将需要额外的努力和时间在 C 和 Python 之间切换,或者一些额外的压力,
最终会降低你的开发效率。
根据 TIOBE 排行,C 仍然是最受欢迎的编程语言之一。尽管事实如此,对 Python 程
序员来说,通常他们很少或者几乎不太了解。就个人而言,我认为 C 在编程世界应该是通
用语言,但是我的意见在这个问题上未必能改变一些事情。Python 非常吸引人,而且很容
易学习,许多程序员忘记了他们以前的经验,完全切换到新的技术上来。编程不像骑自行
车。如果不经常使用,这个特殊的技能很快就会受到侵蚀。即使有强大 C 语言背景的程序
员也有这样的风险,如果他们决定长时间深入使用 Python,他们会逐渐失去他们以前的知
识。上面提到的所有问题会导致这样一个简单的结局:很难找到一个能够理解和扩展你的
代码的人。对于开源的包,这意味着会有更少的自愿贡献者。在闭源代码中,这意味着并
非所有的队友都能够在不破坏原有代码的情况下开发和维护扩展。
调试
当出现错误时,扩展可能会无法运行,这非常糟糕。静态类型提供了许多优于 Python
的优点,可以让你在编译步骤中捕获很多问题。而在 Python 中,如果没有严格的测试例程
和全面的测试覆盖的情况下,就很难发现这些问题。另一方面,所有的内存管理必须手动
操作。并且,错误的内存管理是 C 语言中大多数数编程错误的主要原因。在最好的情况下,
这样的错误只会导致一些内存泄漏,这将逐渐消耗掉你所有的环境资源。最好的情况并不
意味着容易处理。如果没有使用适当的外部工具,如 Valgrind,内存泄漏是非常棘手的。
总之,在大多数情况下,扩展代码中的内存管理问题将会在 Python 中导致无法恢复的段错
误,并且会导致解释器崩溃,并且不会抛出任何异常。这意味着你最终需要使用大多数
Python 程序员不需要使用的额外的工具。这增加了开发环境和工作流程的复杂性。
无扩展的动态库接口
由于 ctypes(标准库中的一个模块)或 cffi(一个外部包),你几乎可以在 Python 中集
成任何一个编译的动态/共享库,无论这些库使用什么语言编写。你可以在没有任何编译步
骤的纯 Python 中这样做,所以这是一个在 C 中编写扩展的一个令人关注的替代方案。
这并不意味着你不需要知道任何关于 C 的东西。这两个解决方案都需要你对 C 有一定的理
解,以及动态库的工作原理。另一方面,他们消除了处理 Python 引用计数的负担,大大降低了
造成严重错误的风险。通过 ctypes 或 cffi 与 C 代码交互比编写和编译 C 扩展模块更容易。
Python 高手编程系列四百六十五:挑战
最新推荐文章于 2024-08-29 19:30:55 发布