Python 高手编程系列六十五:挑战 老实说我用 Python 开启了自己的编程之旅因为我已经厌倦了在用 C 和 C编写软件时的各种困境。事实上我们常常看到程序员开始学习 Python是在他们意识到其他语言不能满足用户需求的时候。与 CC或 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 扩展模块更容易。