这里有一个更简单的方法来解决它
如果我可以使用新的运算符扩展 python 语法以在语言中引入新的功能怎么办?例如,一个新的运算符<=> 用于交换两个变量的值。
如何实现这种行为? AST 模块来了。
最后一个模块是处理抽象语法树的便捷工具。这个模块很酷的地方在于它允许我编写生成树然后将其编译为 python 代码的 python 代码。
假设我们要将超集语言(或类 Python 语言)编译为 Python:
来自:
a <=> b
到:
a , b = b , a
-
我需要将我的“类似 python”的源代码转换为令牌列表。
所以我需要一个分词器,一个 Python 源代码的词法扫描器。 Tokenize module
-
我可以使用相同的元语言来定义新的'python-like'语言的语法,然后构建抽象语法树的结构AST
为什么要使用 AST?
- 在评估不受信任的代码时,AST 是一种更安全的选择
- 在执行代码之前操作树Working on the Tree
from tokenize import untokenize, tokenize, NUMBER, STRING, NAME, OP, COMMA
import io
import ast
s = b"a <=> b\n" # i may read it from file
b = io.BytesIO(s)
g = tokenize(b.readline)
result = []
for token_num, token_val, _, _, _ in g:
# naive simple approach to compile a<=>b to a,b = b,a
if token_num == OP and token_val == '<=' and next(g).string == '>':
first = result.pop()
next_token = next(g)
second = (NAME, next_token.string)
result.extend([
first,
(COMMA, ','),
second,
(OP, '='),
second,
(COMMA, ','),
first,
])
else:
result.append((token_num, token_val))
src = untokenize(result).decode('utf-8')
exp = ast.parse(src)
code = compile(exp, filename='', mode='exec')
def my_swap(a, b):
global code
env = {
"a": a,
"b": b
}
exec(code, env)
return env['a'], env['b']
print(my_swap(1,10))
其他使用 AST 的模块,其源代码可能是有用的参考: