引言
Python [1] 是一种流行的编程语言。Python 和 Lua 都常被嵌入到应用程序中以提供脚本支持。
脚本在游戏中被越来越频繁地使用。选择脚本语言时需要考虑许多因素。这可能是一个简单的决定,取决于目标平台的架构,例如您是在 PC 还是游戏机上。假设您拥有快速的 CPU、虚拟内存和硬盘存储的优势,Python 庞大的库资源可以帮助您更快地完成项目。如果您没有这些优势,Python 就不是一个选项,因为它相当庞大。
总体比较
以下是一个简单的比较,列出了 Python 和 Lua 各自的优势。
Python
- 装备更齐全。拥有大量非常有用的功能库。对于离线工作(例如工具脚本)非常有用。大量的示例脚本 [2]、教程 [3]、帮助 [4] 和通用参考资料 [5]。
- 通过实现真正多维数组的附加模块,可以实现极高性能的数值计算(例如科学和图形)。严格来说,Lua 没有数组,必须使用表结构来表示它们。
- Lua 数组就是表,这是真的。然而,它的实现具有双重性质,并且数组用法(1..N 索引)得到了应有的优化。 -ak
- 另外,Lua 必须使用表来表示数组的说法并不完全正确。使用 userdata 可以创建优化的数组,就像您描述的那样……Blue PiL 中有一个例子。 -nw
- ctypes(Python 2.4 中可用,并计划在 2.5 中核心包含的模块)允许在不编写 C 包装器的情况下访问现有的共享库(.so 或 .dll)。
- Lua 中此功能请参阅 Alien。 [6] -nw
- 拥有远程调试器 [7]。
- Lua 拥有更简单但更简约的语法(并且不可能做得更简单)。不过,差异并不大。请比较 [9][10]。
- Python 拥有对字符串和列表的广泛切片功能,这是一项巨大的生产力提升。我建议那些希望在 Lua 中提高生产力的人使用切片库。
- Python 拥有更广泛(尽管远非完美)的 Unicode 支持。
- Python 是区分空格的。经验丰富的 Python 开发人员知道,一旦“感觉奇怪”的点消失,这不是问题。除了不是问题之外,它还有助于标准化代码的外观,从而促进不同代码库之间的可读性。关于这个问题是问题的谣言通常是由不日常使用它的人传播的,正如 Google 中的一些抽样可以轻易证明的那样。
- Lua 存在一个漂亮的打印机,因此代码可以像 Python 一样“标准化”。-SharkD
- 是的,但你不必使用它。Python 迫使你的代码至少看起来像个样子。巨大的区别。 —MR
- Python 内置了二进制运算符(或、与、异或等)。嵌入式系统非常受益于此,尽管 Lua 可以通过附加库或使用 LuaX 枚举来扩展以包含这些功能。
- Python 具有通过某种程度的静态类型检查来减少错误的能力。Lua 程序更容易出错,因为自动类型转换、在未设置变量时访问而没有异常,以及必须检查大多数函数是否为 nil 值,而不是仅仅捕获异常。然而,其中一些点可能有一些优势。
- 在我看来,解决这个问题的唯一体面方法是静态分析。我的大部分灾难性的全局拼写错误都发生在较少使用的代码路径中,即使
-w幸存下来,它们也会在最糟糕的时候使人们崩溃。因此 LuaLint,我猜我应该在 5.1 上尝试一下…… --JayCarlson - 这是一个更强/更弱[14]类型检查的问题,而不是静态/动态[15]类型检查的问题。 -- xlq
- Python 拥有更多的初学者文档。Lua 仍然缺乏入门材料。
Lua
- 比 Python 更小的占地面积。例如,看看 python22.dll 的大小,824kb。一个基本的 Lua 引擎,包括解析器/编译器/解释器,但不包括标准库,重量不到 100kb。
- 似乎缺少任何指针的使用或实现(引用?)
- USERDATA 和 light USERDATA 呢?
- 这不是真的,所有表都通过引用传递。只需将数据放入一个表(甚至是表中的一个表),然后将其传递给函数。
- 更快的解释器(Lua vs. Python)和更快的 JIT 编译器(LuaJIT vs. Psyco)[17]。
- 拥有一个漂亮的简单 API,用于脚本与 C 之间的通信,所需的胶水代码生成非常少。尝试在 Python 中创建和操作列表和字典,然后在 Lua 中执行相同的操作。
- 不使用对象的引用计数,这可能会变得复杂且容易出错。尽管您可以使用 Python Boost 库(如 [18])这样的东西,如果您喜欢 C++。
- Lua 最初是一个配置语言。这有一些有趣的优点,因为它非常适合创建和配置事物——这正是您在游戏中想要做的。
- 拥有一个漂亮、简单且非常强大的语法。我发现您可以用比 Python 更少的代码在 Lua 中编写相同的内容,并且由于 Lua 的元机制,您拥有更多的灵活性。例如,在 Lua 中,表既是列表又是字典(尽管您可以让它们表现得像 PythonLists 和 PythonDictionaries)。匿名函数对于配置事物也特别好。在 Python 中,您得到的是它们的廉价表亲:lambda 函数。
- 代码库小巧、简单、稳定。容易深入研究和修改。可能不如 Python 文档齐全。
- 实际上并不容易深入研究。而且注释真的不多。-jv
- 我不同意。我发现深入研究 Lua 源代码并对其编译器和 VM 进行修改非常简单。代码库非常干净且经过深思熟虑。- bp
- 借助这本书,我发现代码库直接且易于修改。我经常将自定义 Lua 引擎与我的软件一起打包,并且能够做到这一点对资源的最小影响对我来说非常有价值。- mw
- 很少的外部模块使 Lua 更容易为特定目的进行捆绑,即使标准构建功能不足。与 Python 的众多模块(包括标准发行版附带的库)相比。
- Lua 支持多线程。多个 Lua 解释器可以存在于同一进程中,并且每个解释器都可以独立运行在其自己的线程中。因此,Lua 更适合嵌入到多线程程序中。
- Lua 不区分空格。虽然与 Python 相比这有一些缺点,但无需担心自动编辑器空格到制表符的转换或反之。当使用比例字体时,Lua 允许使用任意数量的缩进,以使代码易于阅读。
- Lua 对单个线程或进程中的多线程和多个解释器提供开箱即用的支持。Python 不支持单个进程中的多线程和多个解释器。多个线程可以访问 Python 解释器,但每个线程在这样做时都必须持有全局锁。
- 这是不正确的。“全局解释器锁”(GIL)顾名思义是每个解释器的,而不是每个进程的;您实际上可以在单个进程中嵌入多个解释器。 -JonathanEllis?
- 原始作者是正确的,GIL 是每个进程的。您可以拥有多个解释器,但它们只是一个作用域的东西,它们不允许多个并发线程运行。请参阅 [19] 获取我发现的最简洁的讨论。
- 但是,原始作者在“Python 不支持单个进程中的多线程和多个解释器”的陈述中仍然是错误的,这取决于您如何解释它。GIL 是每个进程的。您可以拥有多个解释器。您也可以拥有多个线程。这些可以同时在同一进程中的同一个或不同的子解释器中运行。然而,当任何一个特定线程在 Python 代码中运行时,它都会获取 GIL,这样做会阻止任何其他需要 GIL 的线程在此时运行。因此,尽管您可以同时拥有多个线程,但对于 Python 绑定代码,您无法有效地并发运行它们。这意味着,例如,两个 Python 线程不能同时利用系统上的两个不同 CPU 或核心。只有当 Python 代码进入 C 代码并且由于不需要 GIL 时线程释放它时,情况才不是这样。那时,在 C 代码部分运行的线程可以与 Python 绑定线程并发运行。因此,Python 扩展模块在不需要 GIL 时应始终释放 GIL。包装了大量 C 库的 Python 扩展模块,其中数据与 Python 有足够的可区分性以允许释放 GIL,因此仍然可以看到真正的并发。
- 即使进行了上述更正,这也仅适用于 CPython 解释器。其他 Python 实现,如 Jython、
IronPython 和 PyPy,没有全局解释器锁。
- 最后一句话是错误的;
PyPy 就像 CPython 一样有 GIL。请参阅 [20]
- 然而,陈述的其余部分是正确的。GIL 限制并非在所有实现中都存在。它肯定不是
IronPython 的限制。我假设 Jython 也不是限制,因为它们之间有很多相似之处,尽管我没有 Jython 的个人经验。- KJR - PyPy? STM 是一个没有 GIL 的 PyPy? 实现。-JKH
面向对象
基于 OO 模型进行的比较将在此处跟进
Python
- 规定了面向对象编程的特定模型。Python 拥有丰富的 OO 功能,包括元类、多重继承等。
Lua
- 不规定任何特定的 OO 系统。相反,您可以构建自己的系统(使用元方法)并根据您的需求进行定制。
摇摆不定
- 它们都有自动绑定生成器。SWIG 对两者都有效。Lua 还有 toLua(已经有一段时间没有开发了,但适用于 4.0 - 不确定 4.1)。更新:现在有一个 toLua 5.0a,效果很好!
- Lua 的表索引从 1 开始,这对于一门旨在与 C 交互的语言来说很奇怪,因为 C 中的数组从 0 开始。(评论:临时措施,使用索引 0 甚至 -1 没有问题……所以如果您是 C 程序员,您可以使用“t[0]=t[-1]”等。但如果您不是程序员……例如,对于技术计算,您会发现表 t[1..n] 更熟悉)
- Lua 只处理一种数字类型,通常是 C double 或 float,这可能导致处理过载。
- 您应该看看 Python 在相加两个整数时所做的工作,并考虑“处理过载”可能意味着什么。(例如,在 Python 中,每个超出范围 [-1, 100) 的整数都将被重新分配)。
- Lua 的数字类型可以在编译时轻松更改为 double、float,甚至 long 或 int(如果您不关心浮点数……)。但确实需要有单独的 int 和 number 类型,我同意。 -ak
- ''Lua 5.3.x 引入了 int 子类型。
- CPython 解释器有一个名为 Cython 的扩展语言 [21],它使用与 Python 相同的语法和语义,但使用优化编译器将其转换为 C 代码。这使得通过与 Python 语言良好集成的包装器可以轻松地与 C、C++ 和 Fortran 代码集成。这在 Lua 世界中是无与伦比的。Cython 还为 Python 代码提供了一条直接的优化路径,可以生成快速的、手动优化的计算代码,通常可以胜过可用的 JIT 编译器。Lua 结合 LuaJIT 对于计算代码已经非常快了,因此可能不需要这种手动优化路径。
参考文献
- Crystal Space [22] 支持这两种语言。提供的源代码可能提供有用的信息来帮助决定其适用性。更新:由于缺少 swig,lua 可能停滞不前
- Nebula Device [23] 也支持这两种语言以及 TCL。
用户意见
请不要在这里挑起战争。请随意就您的经验发表简单客观的陈述。
- 我可以在哪里阅读有关 Lua 的“-w”选项的信息?Google 找不到任何东西。-- Alex
- 不再存在。在 https://lua-users.lua.ac.cn/lists/lua-l/ 中搜索“lua -w”(带引号)。请参阅 DetectingUndefinedVariables。DavidManura
- 我认为我曾尝试将两者都用于游戏和工具。Python 更适合离线工具,Lua 更适合嵌入和配置。Python 拥有大量非常有用的库可用于大多数任务,而 Lua 小巧、快速且高度可配置,非常适合嵌入。-- NickTrout
- 在 Python 中,所有都是在堆上分配的对象,包括数字。(所以 123+456 会创建一个新的堆对象)。我认为这可能是速度差异的一个重要因素。--JeffPetkau
- Lua 5.0 对协程(或称延迟函数或其他名称)有极好的支持,这对于游戏脚本非常重要。Stackless Python 也有它们,但它们从未进入核心。(这是我们决定在引擎中使用 Lua 而不是 Python 的*关键*问题。)--JeffPetkau
- 一个基于此做出整个决定的奇怪点。Python 的生成器与即将推出的 Lua 的有限协程相同。请参阅 LuaList:2002-07/msg00174.html。
- 它们有关联,但并不相同。Lua 的协程更通用。另外,我们并没有完全基于这一点做出决定;这只是决定天平倾斜的问题。
- Python 的生成器从历史上看不是“相同”的协程:请参阅 https://pythonlang.cn/dev/peps/pep-0342/ 以了解 Python 最近对支持协程的更改。
- 通过使用 Codespeak 库(Debian 包 python-codespeak-lib)中的 greenlets,可以非常方便地为 Python 提供良好的协程支持,而无需使用功能齐全的 Stackless。--SeanHoldsworth
- 但这真的有助于递归生成器吗?请参阅 LuaCoroutinesVersusPythonGenerators
- Python(对我而言,一个学习 Gary 的模组 Lua 的人,以及一个狂热的 Python 用户)似乎是 Lua 几乎想成为的样子,例如 Python 的一切都是指针的态度规则,它的导入而不是包含东西,以及你所做的一切都是一个对象的整个事实,关于它的内存管理有传言说相当……嗯,很糟糕,但似乎 Python 3000 解决了这个问题。
- 我将添加一条关于 Python 指针态度的注释,以及我如何还没有找到;好吧,Lua 有“引用”,它们……很奇怪,在 Python 中,一个人仍然可以很容易地复制变量。
- 当您想在代码中添加一个小占地面积时,Lua 是理想的选择:据我所知,它是目前可用的最小的脚本引擎。这就是我选择它来开发 Lixoo(一个 2D 冒险游戏引擎)的原因。我的目标之一是,一个随时可用的 Lixoo 发行版(包括引擎和基本开发工具)的重量必须小于一兆字节。-- AdrianPerez
- Lua 拥有 Lisp/Scheme 的强大功能,但语法简单且实现出色。我对 Lua 在嵌入式(实时)应用中的表现非常感兴趣。它的核心很小,它的设计允许灵活性。特殊的语言特性,例如对象中状态相关的函数集,可以通过元表轻松实现。状态也可以保存在协程中。这些都是我曾希望在 Python 中拥有的东西。然而,Python 在其丰富的库、出色的文档和漂亮的语法方面表现出色。我不喜欢用“end”来结束每个块,我已经不习惯了;-)最后但同样重要的是,有些错误会在 Python 中导致异常,例如除零错误,无论数字类型(double/integer)如何,而我认为 Lua 在编译期间捕获的错误更多。然而,我假设 Python 会迎头赶上。PyChecker? 等工具已经可用,并且一些想法有望集成到核心中。我喜欢这两种语言,并将它们用于不同的目的。-- Dominic
- 我曾经并且仍然是 Python 的狂热用户。我从未在嵌入式场景中使用过 Python,因为我觉得它太痛苦了。当我遇到 Lua 3.2 时,我感觉有人打开了我的头骨,找到了我对 Python 嵌入的所有批评,然后用它来创建一个我想要的语言和环境。
- 从那时起,我当然继续使用 Python。我发现 Python——因为它拥有庞大的库集——更适合通用脚本和 RAD 工作。我对 Python 的语法也很熟悉,即使有其怪癖,所以我的手指自然会按照 Python 的方式做事。(我在 Lua 中使用'.'而不是':'作为方法访问器而被烫伤的次数会让大多数人捧腹大笑。)然而,我笑的是即使是使用 Python 进行任何嵌入式操作的任何一丝可能性。Lua 是我那里的首选工具。-- MichaelRichter
- Pythonic 的方式是扩展而不是嵌入。在 Python 社区中,嵌入被认为是不应该做的事情。(有关为什么的简要解释,请参阅 http://www.twistedmatrix.com/users/glyph/rant/extendit.html。)Lua 很好地填补了 Python 避免的领域。另一方面,我认为 Lua 的一些不错的动态库支持会很有帮助。(我是那篇咆哮的作者,我不认为它一定反映了 Python 社区的主流观点。我希望如此——我确实认为大多数嵌入只是迎合了 C 程序员的不安全感和误解,而不是满足了真正的技术需求。在相关说明中,我一直在等待 Lua 认识到它是一门真正的编程语言,并停止搞这个“脚本”垃圾……)(我不是那篇咆哮的作者,这是我第一次读到它“永远不应该做”。Blender、OpenOffice? 等肯定会表明事实并非如此。您也可以阅读 [24] 来查看事实并非如此)。
- 我广泛使用 Python 进行游戏开发,我认为如果您正在寻找一种可以轻松嵌入引擎以创建实体逻辑或配置/调整脚本的语言,Lua 可能是更好的选择。Python 是一种强大的通用语言,您将为此付出集成复杂性、性能和内存要求的代价。然而,如果您正在寻找一种可以取代您许多模块中的 C 或 C++ 的高生产力语言,Python 显然是更好的选择(如上所述,这最好通过 Python 扩展而不是嵌入来完成)。Lua 是为小型脚本设计的,无法与 Python 在大型开发方面竞争。-- Camelo
- 我是一名脚本新手,我打算比较不同的替代方案,然后再选择一个用于我的 3D 游戏引擎。我花了三个小时才让 Lua 5 的基本嵌入和扩展工作正常。我心想,“这个脚本的东西没那么难!”,然后转向了 Python。经过四天的痛苦和沮丧,在我为 Python C-API 感到痛苦之后,尝试让 Boost.Python 编译 Python 2.3,尝试 CXX 和 SWIG 以及其他我知道什么,并尝试在 Visual Studio 6 下使用 windows.h 运行它们(这导致了多个相互不兼容),我发现了 luabind,我认为我再也不会回头看 Python 了。-- Mike
- 给 Mike 的一个简短评论:虽然我从未使用过,但 Boost.Python 不适用于 Python 2.3,而是适用于 2.2。请参阅 [25]。-- Thomas
- 我不确定这个引用是什么时候做的,但是,您可以轻松地切换 Python Boost.Python 编译的目标版本,目前是这样的。然而,我发现嵌入 Python 有点麻烦。最值得注意的是,它的全局解释器锁机制对于多线程 C++ 应用程序有点麻烦。
- Boost.Python 1.33.1 新闻:构建现在默认假定为 Python 2.4,而不是 2.2。-- AnonymousDonor?
- Python 的作用域,即使有了“新”的嵌套作用域,也非常有限且容易出错。循环等结构不会打开新作用域,因此无法在其中创建私有变量。例如,如果您在循环中创建了一个与循环之前的内容同名的变量:您将覆盖外部变量。在 Python 中没有办法解决这个问题,除非您小心名称冲突,或者使用大量嵌套函数来打开新作用域。相比之下,Lua 在这种情况下为您提供了精确的控制:在循环中,您可以使用
local创建一个私有变量,或者省略它并写入外部变量。--JohnBelmonte
- 根据我的经验,从外部作用域隐藏变量是容易出错的,而 Python 阻止了这一点。函数内的一个名称指向两个不同的对象肯定会使人困惑。事实上,许多 C++ 风格指南建议不要隐藏变量。Python 强调可读代码,并且不允许您想要的这种行为实际上是朝着这个方向迈出的一步。--AnonymousDonor?
- 在 C# 中,隐藏变量是错误。我喜欢这样——我希望编译器通知我任何歧义,并让我消除歧义(通过使变量名在函数内唯一)-- BjarkeDahlEbert
- 是的,从外部隐藏变量可能会有问题,但我们都喜欢为变量使用描述性名称,所以最后您会遇到问题,例如我无法获取名称 value_index,因为它上面已经使用过了,我需要输入 local_value_index,最后我们得出 Lua 使用的解决方案。
- 我都是这两种语言的新手,但我想说这两种语言似乎都很有 power,但它们的工作方式不同。我想说 Python 和 Lua 之间的区别就像 Java 和 C 之间的区别一样。像 Java 一样,Python 很大,有大量的库,相当慢,但功能丰富。另一方面,像 C 一样,Lua 轻巧,几乎在所有平台上都有实现,但对用户设计好帮助较小。--Xavier
- 我花了很多时间研究要嵌入到 C++ 程序中的脚本语言,最终归结为 Python 或 Lua。在花了整整一天的时间尝试让 boost.python 工作后,我放弃了,因为我甚至无法使用 bjam 编译一个简单的 Hello World 程序。除此之外,我没有找到一种好的方法来只向 Python 解释器添加一些全局变量(它们是指向 C++ 类的指针),并且我不喜欢 boost.python 的语法或实现虚函数的语法。总之,我决定花几个小时看看我能用 Lua 走多远,并使用 tolua++ 我能够公开数十个类的所有公共方法和变量,并且一切都如我所料。是的,虚函数实现不起作用,我也无法从 C++ 接口派生以创建新的 Lua 类,但我可以忍受。都不是完整的解决方案,但任何东西都比用 C++ 实现所有这些要好。--Tom
- 给那些在 Python 上与 SWIG 或 Boost 等工具斗争过的人一个快速提示——我发现了
PyInline [26],它就像魔法一样。我只需要用一些 C 代码制作一个字符串,调用“make”,然后我就可以调用 Python 例程了!它在 XP 和 Fedora 上运行良好,使用完全相同的源代码。在包含方面有一些怪癖,但对于简单的粘合到 .so 或 DLL,它非常有用。也就是说,我正在为一些机器人项目寻找一个超小的核心可嵌入语言,到目前为止 Lua 看起来很不错。
- 那些抱怨 Python-C API 危险性的人应该看看 Pyrex。我还没有亲自使用过它,但我认为我将在我的下一个游戏中这样做。它具有 Pythonic 语法,但可以使用 C 数据类型,因此您可以更轻松地为 Python 编写 C 模块。当然,这仍然是扩展 Python 而不是嵌入它。如果我发现我没有使用 Python 的很多附加功能或稳定性,我可能会改用 Lua。
- 选择最适合工作的工具。如果我想做一个一次性的独立程序来做一些字符串处理(通常是为了支持我妻子的业务),我会用 Python。对于为大型嵌入式系统添加脚本功能,Lua 更好一些。对于编写大型、复杂的程序,C++ 是我的首选工具。对于修改或为 WordPress? 网站添加功能,PHP 是阻力最小的途径,但我发现自己希望有人用 Python 重写那个烂摊子。
另请参阅
RecentChanges · preferences
编辑 · 历史
最后编辑于 2018 年 9 月 19 日 上午 9:54 GMT (差异)