使用 Python v3.x 和 C API 解释 Python v2.5 代码(关于整数除法)



我有一个我无法控制的v2.5 Python代码,因为它是从支持Python v2.5的第三方软件导出的。

我的机器上有Python v3.3,我想以某种方式模拟v2.5 使用 C API。我主要关心的是 v2.x 和 v3.x 之间的整数除法。

例如,我有下面的代码:

a=1
b=a/2
c=a/2.

我希望以某种方式将其解释为(使用 v3.x):

a=1
b=a//2
c=a/2.

我能做些什么吗?有没有办法像我有Python v2.5一样解释代码?我想 2to3 脚本不适用于我的情况,六个模块也不起作用。

我还发现了与我相关的这个问题: Python 2 和 Python 3 双重开发

谢谢

这听起来是个坏主意——你将遇到更严重的问题,将 Python 2.5 代码解释为 Python 3,比如每个except语句都是语法错误,字符串是错误的类型(或者,如果你修复了这个问题,s[i]返回一个 int 而不是一个字节),等等。


这里要做的显而易见的事情是将代码移植到仍然受支持的 Python。

如果由于某种原因这真的是不可能的,最简单的事情可能是围绕你需要运行的代码编写一个微不足道的 Python 2.5 包装器,它通过sys.argv和/或sys.stdin获取输入,并通过sys.exit和/或sys.stdout返回结果。

然后,你只是这样称呼它:

p = subprocess.run(['python2.5', 'mywrapper.py', *args], capture_output=True)
if p.retcode:
raise Exception(p.stderr.decode('ascii'))
results = p.stdout.splitlines().decode('ascii')

但如果你真的想这样做,这真的是你唯一的问题......这仍然不是这样做的方法

您必须进入C API级别以下,进入内部类型对象(如struct PyFloat_Type),访问其tp_as_number结构,并将其nb_floordiv函数复制到其nb_truediv槽。即使这样也可能无法改变一切。


更好的解决方案是在编译 AST 之前构建一个转换 AST 的导入钩子。

编写导入钩子可能是一个太大的主题,无法在几段中作为答案的序言来涵盖,因此请参阅该问题的该部分。

现在,至于导入钩子的实际作用,您要做的是替换MyLoader.exec_module方法。取而代之的是:

def exec_module(self, module):
with open(self.filename) as f:
data = f.read()
# manipulate data some way...
exec(data, vars(module))

你要这样做:

def exec_module(self, module):
with open(self.filename) as f:
data = f.read()
tree = ast.parse(data)
# manipulate tree in some way
code = compile(tree, self.filename, 'exec')
exec(code, vars(module))

那么,我们如何"以某种方式操纵树"呢?通过建立NodeTransformer.

每个/表达式都是一个BinOp节点,其中op是没有属性Div节点,leftright是要划分的值。如果我们想将其更改为相同的表达式但带有//,那是相同的BinOp,但opFloorDiv

因此,我们可以只访问Div节点并将它们转换为FloorDiv节点:

class DivTransformer(ast.NodeTransformer):
def visit_Div(self, node):
return ast.copy_location(ast.FloorDiv(), node)

我们的"#以某种方式操纵树"变成了:

tree = DivTransformer().visit(tree)
如果你想根据除

数是否是整数文字在floordivtruediv之间进行选择,正如你的例子所暗示的那样,这并不难:

class DivTransformer(ast.NodeTransformer):
def visit_BinOp(self, node):
if isinstance(node.op, ast.Div):
if isinstance(node.right, ast.Num) and isinstance(node.right.val, int):
return ast.copy_location(ast.BinOp(
left=node.left,
op=ast.copy_location(ast.FloorDiv(), node.op),
right=node.right))
return node

但我怀疑这是否是你真正想要的。事实上,你真正想要的可能很难定义。您可能想要类似以下内容:

  • floordiv运行时,如果两个参数都是整数值
  • floordiv最终控制__*div__/__*rdiv__的参数(通过精确复制解释器为此使用的规则)是否是一个整数值。
  • 。别的?

无论如何,执行此操作的唯一方法是将BinOp替换为mydiv函数的Call,您编写并例如,粘贴builtins。然后,该函数执行类型切换以及实现规则所需的任何其他操作,然后return a/breturn a//b

相关内容

  • 没有找到相关文章

最新更新