可以用python ast模块吗?

1 投票
4 回答
561 浏览
提问于 2025-04-16 00:08

我想写一个程序,用来修改Python程序,具体是这样的:

"某个固定字符串 %" % SOMETHING

改成

functioncall("某个固定字符串 %") % SOMETHING

谢谢!

4 个回答

0

这里有另一个可能有用的StackOverflow问题。

我了解到,ast模块并没有提供将其转换回源代码的功能。不过,Armin Ronacher写了一个名为codegen的模块,它实现了一个to_source函数,可以做到这一点,专门用于ast节点。

我自己还没有尝试过这样做。

1

你可以不写程序就解决这个问题。只需使用一个非常棒的编辑器:Emacs。如果你还没学过,真心推荐你去学一下。用它的话,你可以利用它的正则替换功能来解决这个问题。唯一的问题是,我很少用正则表达式,所以总是忘记那些复杂的语法细节,还得去查资料 :P 我会再帮你弄明白的。这里有一个链接,提供了关于Emacs的搜索和替换信息 - 向下滚动可以找到正则表达式的用法

2

使用 tokenize 可能会更简单——我们可以根据文档中的例子来调整一下。

import cStringIO
import tokenize

class Lookahead(object):

  def __init__(self, s):
    self._t = tokenize.generate_tokens(cStringIO.StringIO(s).readline)
    self.lookahead = next(self._t, None)

  def __iter__(self):
    return self

  def next(self):
    result = self.lookahead
    if result is None: raise StopIteration
    self.lookahead = next(self._t, None)
    return result


def doit(s):
  toks = Lookahead(s)
  result = []
  for toktype, tokvalue, _, _, _ in toks:
    if toktype == tokenize.STRING:
      pk = toks.lookahead
      if pk is not None and pk[0] == tokenize.OP and pk[1] == '%':
        result.extend([
            (tokenize.NAME, 'functioncall'),
            (tokenize.OP, '('),
            (tokenize.STRING, repr(tokvalue)),
            (tokenize.OP, ')')
        ])
        continue
    result.append((toktype, tokvalue))
  return tokenize.untokenize(result)


print doit('"some literal string %" % SOMETHING')

这段代码会输出 functioncall ('"some literal string %"')%SOMETHING。这里的空格看起来有点奇怪(要把空格调整得恰到好处需要花费很多精力——而且如果你想从修改过的抽象语法树(AST)重建源代码,那就更麻烦了),不过如果你只是想导入或运行生成的代码,那就没问题了(如果你想得到可读性和可编辑性都很好的代码,那就不太好了——不过这是个比较大的问题,我建议另开一个问题来讨论;-)。

撰写回答