为什么无法创建实用的Perl到Python的源代码转换器?
如果有一个程序能自动把Perl代码转换成Python代码,那就太好了,这样生成的Python程序不仅能正常工作,还能和原来的代码一样易读和好维护。
最简单的办法就是通过Python工具调用perl
:
#!/usr/bin/python
os.exec("tail -n -2 "+__file__+" | perl -")
...the rest of file is the original perl program...
不过,这样得到的代码几乎还是Perl代码,根本算不上Python代码。一个理想的转换器应该把Perl的结构和用法转换成易读的Python代码,同时保留变量和子程序的名字(也就是说,结果不能看起来像是乱码),而且不能破坏原有的工作流程。
这样的转换显然很难。转换的难度取决于Perl的特性和语法结构,而这些在Python中没有简单易读、不模糊的对应写法。我认为,Perl中有很多这样的特性,使得自动转换在实际操作中几乎不可能(虽然理论上是有可能的)。
那么,能不能列举一些Perl的用法和语法特性,这些在Python中无法像原来的Perl代码那样简洁地表达呢?
编辑:有些人提到了Python转Perl的转换器,并因此推测写一个Perl转Python的转换器应该很简单。然而,我相信转换成Python的需求更大;尽管如此,这个转换器还没有被写出来——而反向的转换器已经存在了!这让我对写出一个好的Perl转Python转换器的可能性更加怀疑。
12 个回答
为什么Perl不是Python。
Perl有一些Python几乎没有的语句。虽然你可能可以想办法用Python写出类似的语句,但语法会和Perl完全不同,这样就很难称之为“翻译”。你真的需要想出一些复杂的Python代码,才能让它看起来和原来的Perl一样简洁。
Perl的运行时语义和Python差别很大,这让翻译变得非常困难。下面我们就来看一个例子。
Perl的数据结构和Python有很大不同,这也让翻译变得困难。
Perl的线程默认不共享数据。只有特定的数据元素可以共享。而Python的线程则更常见“共享所有数据”的方式。
下面的例子可以说明第二点。
Perl代码:
do_something || die()
其中 do_something 是任何类型的语句。
要把这个自动翻译成Python,你必须把每个 || die()
语句包裹在
try:
python_version_of_do_something
except OrdinaryStatementFailure, e:
die()
sys.exit()
更常见的写法是
Perl
do_something
用简单的、没有思考的方式翻译源代码会变成这个
try:
python_version_of_do_something
except OrdinaryStatementFailure, e:
pass
当然,
Perl
do_this || do_that || die()
翻译成Python会更加复杂。
而且
Perl
do_this && do_that || die()
真的很有挑战性。我的Perl有点生疏,所以我记不清这种情况的确切语义。但你必须完全理解这些语义,才能找到合适的Python实现。
这些Python示例并不是好的Python代码。写出好的Python需要“思考”,而自动翻译是做不到的。
每个Perl的结构都必须像这样“包裹”起来,才能把原来的Perl语义转换成Python的形式。
现在,针对Perl的每一个特性做类似的分析。
你最好的Perl转Python的转换工具,可能就是一个23岁刚大学毕业、正在找工作的年轻人。
为了更好地理解这里提到的一些内容,下面列出了一些在Python中可能会显得很笨拙的Perl特性(如果能实现的话)。
- 动态作用域(通过
local
关键字实现) - 类型全局操作(多个变量可以同名)
- 格式(它们有自己独特的语法)
- 对可变变量的闭包
- 编译指令
- 左值子程序(像
mysub() = 5;
这样的代码) - 源过滤器
- 上下文(列表和标量的区别,以及调用代码如何使用
wantarray
来检查这一点) - 类型强制/动态类型
- 任何使用字符串
eval
的程序
这个列表还可以继续列下去,可能有人会尝试在这些相似的特性之间建立对应关系,但最终会失败,原因很简单。
Perl代码无法静态解析。Perl代码中的定义(特别是在BEGIN块中的定义)会改变编译器对后续代码的解释方式。因此,对于复杂的程序,从Perl转换到Python时会遇到停机问题。
在程序运行结束之前,无法确切知道整个程序将如何被编译,理论上可以创建一个每次运行时编译结果都不同的Perl程序。这意味着一个Perl程序可能对应无数个Python程序,而正确的Python程序只有在原始程序在Perl解释器中运行后才能确定。