这听起来是个坏主意——如果将 Python 2.5 代码解释为 Python 3,您将遇到更严重的问题,例如每个except
语句都是语法错误,字符串类型错误(或者,如果您解决了这个问题,则s[i]
返回一个int 而不是一个字节),等等。
这里要做的显而易见的事情是将代码移植到仍然受支持的 Python 上。
如果由于某种原因这确实是不可能的,那么最简单的做法可能是围绕您需要运行的代码编写一个简单的 Python 2.5 包装器,该包装器通过 and/or 获取输入并通过and sys.argv
/orsys.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 之前对其进行转换。
编写导入钩子可能是一个太大的话题,无法在几段中作为答案的前言来涵盖,所以请参阅这个问题的那部分。
现在,至于 import 钩子实际上做了什么,你要做的是替换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
isDiv
没有属性的节点,left
andright
是要划分的值。如果我们想将其更改为相同的表达式,但使用//
,那是相同的BinOp
,但在op
哪里FloorDiv
。
所以,我们可以只访问Div
节点并将它们变成FloorDiv
节点:
class DivTransformer(ast.NodeTransformer):
def visit_Div(self, node):
return ast.copy_location(ast.FloorDiv(), node)
我们的“#以某种方式操作树”变成:
tree = DivTransformer().visit(tree)
如果您想根据除数是否为整数文字进行选择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
如果最终将控制__*div__
/的参数__*rdiv__
(通过精确复制解释器为此使用的规则)是一个整数值。
- ……别的?
无论如何,这样做的唯一方法是BinOp
用 a替换你编写Call
的mydiv
函数,例如,插入builtins
. 然后该函数执行类型切换以及实现您的规则所需的任何其他内容,然后是return a/b
or return a//b
。