使用PythonV3.x和C API解释PythonV2.5代码(关于整数除法)
我有一个无法控制的2.5版Python代码,因为它是从支持Python 2.5的第三方软件导出的 我的机器上有Python v3.3,我希望以某种方式模拟v2.5 使用C API。我主要关心的是整数除法,它不同于v2.x和v3.x 例如,我有以下代码:使用PythonV3.x和C API解释PythonV2.5代码(关于整数除法),python,python-3.x,integer-division,python-2.5,c-api,Python,Python 3.x,Integer Division,Python 2.5,C Api,我有一个无法控制的2.5版Python代码,因为它是从支持Python 2.5的第三方软件导出的 我的机器上有Python v3.3,我希望以某种方式模拟v2.5 使用C API。我主要关心的是整数除法,它不同于v2.x和v3.x 例如,我有以下代码: a=1 b=a/2 c=a/2. 我希望(使用v3.x)以某种方式将其解释为: 我能做点什么吗?是否有任何方法可以将代码解释为Python v2.5?我认为2to3脚本不适用于我的案例,也不适用于六模块 我还发现了与我相关的这个问题: 谢谢这
a=1
b=a/2
c=a/2.
我希望(使用v3.x)以某种方式将其解释为:
我能做点什么吗?是否有任何方法可以将代码解释为Python v2.5?我认为2to3脚本不适用于我的案例,也不适用于六模块
我还发现了与我相关的这个问题:
谢谢这听起来是个糟糕的主意,您将遇到更严重的问题,将Python 2.5代码解释为Python 3,就像每个
一样,除了语句是语法错误,字符串是错误的类型(或者,如果您解决了这个问题,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级别以下的内部类型对象,例如,访问它们的tp\u as\u number
结构,并将它们的nb\u floordiv
函数复制到它们的nb\u truediv
插槽中。即使这样,也可能不会改变一切
更好的解决方案是构建一个导入钩子,在编译AST之前对其进行转换
编写一个导入钩子可能是一个太大的主题,不可能在几个段落中作为一个答案的序言来涵盖,所以请参见这一部分
现在,至于导入钩子的实际作用,您要做的是替换MyLoader.exec\u模块
方法。与此相反:
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))
那么,我们如何“以某种方式操纵树”?通过建立一个
每个/
表达式都是一个BinOp
节点,其中op
是不带属性的Div
节点,左
和右
是要分割的值。如果我们想用/
将其更改为相同的表达式,这是相同的BinOp
,但是op
是FloorDiv
因此,我们只需访问Div
节点,并将它们转换为FloorDiv
节点:
class DivTransformer(ast.NodeTransformer):
def visit_Div(self, node):
return ast.copy_location(ast.FloorDiv(), node)
我们的“以某种方式操纵树”变成:
如果您想根据除数是否为整型文字在floordiv
和truediv
之间进行选择,正如您的示例所暗示的,这并不难:
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
如果最终控制\uuu*div\uuu
/\uuu*rdiv\uuu>的参数(通过精确复制解释器为此使用的规则)是整数值
- …还有别的吗
无论如何,唯一的方法是将BinOp
替换为调用您编写的mydiv
函数,例如,插入内置
。然后,该函数执行类型切换以及实现规则所需的任何其他操作,然后返回a/b
或返回a//b
您的意思是a//2
不起作用?Python3-x将其定义为“整数除法”。@usr2564301不,他说他希望他的Python3解释器在Python2上下文中解析b=a/2
,也就是说:b=a//2
将第三方库移植到Python3。Python2.5和Python3.3在几年前就已经达到了支持生命的尽头。或者只是在Python2.5中作为子进程运行Python2.5代码。“我的机器上有Python3.3”也可以获得2.5。“软件包管理器”在这方面非常出色,因此您可以为不同的版本创建不同的环境。他们希望将a/2.
视为truediv,而不是将所有分区转换为floordiv。@user2357112我添加了一个部分来实现这一效果。如前所述,这不是一个定义明确的要求。而弄清楚如何定义它实际上是困难的一部分。例如,即使a
是浮点数,他们是否真的希望a/2
成为truediv?@abarnert谢谢你的回答。由于我是Python新手,因此我将进一步研究它。然而,为了回答您的问题,我希望在理想情况下这样做:python3.像python2x一样解释(代码为v2x)。我希望得到与使用python v2.x解释器时相同的结果。@tsahmatsis是code\u v2x
源代码吗?函数对象?模块名称…?而且,正如我在问题中提到的:是否有一个原因不能仅仅是子流程.run(['python2.5','code_v2x.py',…一些参数…],…)
?因为到目前为止,这是最容易做到的。@abarnert code_v2x是源代码,应该用与Python v2.x使用v3.x相同的方式来解释。
tree = DivTransformer().visit(tree)
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