如何解析python代码以识别全局变量的使用?

如何解析python代码以识别全局变量的使用?,python,parsing,Python,Parsing,我正在使用python解析python代码。假设我正在解析的代码是: def foo(): global x, y x = 1 y = 2 print x + y 我想在代码中找到全局x和y的所有用法。我有一个提前使用的globals列表,所以没有必要从globals行提取x和y。因此,问题是:给定一些python代码中使用的已知全局变量列表,例如本例中的[x'、[y'],如何解析代码以找到这些全局变量的用法?这将满足您的要求: vars = ['x', 'y'

我正在使用python解析python代码。假设我正在解析的代码是:

def foo():
    global x, y
    x = 1
    y = 2
    print x + y

我想在代码中找到全局x和y的所有用法。我有一个提前使用的globals列表,所以没有必要从globals行提取x和y。因此,问题是:给定一些python代码中使用的已知全局变量列表,例如本例中的[x'、[y'],如何解析代码以找到这些全局变量的用法?

这将满足您的要求:

vars = ['x', 'y']
with open('filename') as fin:  
    for ln in fin:
        vals = ln.split()
        for var in vars:
            if var in vals:
                print ln

这将花费您相当多的时间,因为查找变量不是一项简单的解析或regexp工作。让我们来考虑这个例子:

def foo():
    global x, y
    x = 1  # x is one
    y = 2
    print x + y

    def x(y):
        x print y

    class x:
        y = 'lol'
在这里,我们使用
x
y
有一些有效和无效的情况。您可以尝试保持简单,编写一个脚本来跟踪正在解析的行的上下文(无论是函数定义还是类变量),并包含您可以想到的所有使用全局变量的情况

形式化方法是使用和分析器。词法分析器解析代码并将词素(单词)发送到语法分析器,语法分析器基本上是一个程序,用于确定词素流是否(以及如何)适合某种语言。非正式地说,形式语法是一套规则,决定语言应该是什么样子:

<global_definition> ::= 'global' <variables_list>
<varirable_assignment> ::= <variable> '=' <expression>
# and so on
::=“全局”
::=  '=' 
#等等
这是一项繁重的工作,但幸运的是它是在Python标准库中完成的。正如@LukaRahne所提到的,模块将是一个良好的开端。另一方面,如果您对
ast
后端(以及一般如何使用源代码控制计算机)感兴趣,我建议您阅读
编译器理论
教科书或文章


我为我在这里犯的英语错误道歉。我还没有掌握它的形式语法。

您可以使用ast解析python代码

from __future__ import print_function
import ast

src = """def foo():
    global x, y 
    x = y = 1
    y = 2
    print x + y"""


s = ast.parse(src)

gvars = set()
for i in ast.walk(s):
    # get globals
    if isinstance(i,ast.Global):
        for j in ast.walk(i):
            gvars = gvars.union(i.names)
    #get id-s of globals
    for (field_type,value) in ast.iter_fields(i):
        if field_type == "id" and value in gvars:
            print(value , "at line", i.lineno)
这个输出

x at line 3
y at line 3
y at line 4
x at line 5
y at line 5
就作用域而言,这仍然不能正常工作,但仍然可以在源代码中找到某个id的所有实例

作用域解析问题的示例:

global x,y
def foo():
    x = y = 1 
    global y
    x = y = 2
    # only global y is 2

def bar():
    #here x and y are not global
    x = y = 3

foo()
bar()
print(x,y) # runtime error. x undefined 
我们希望我们的代码只产生
-条形函数中的y
-末端的x,y

但是它打印了所有出现的x,y

问题有些模糊这也会发现
x
y
都是指同名的局部变量,所以它实际上并不能解决问题。所以你在寻找一些能理解范围的东西——如果你有同名的本地人,你在掩盖全局,这是很糟糕的编码,而且我只是想让提问者继续提问,因为问题是模糊的,我不是写问题的人,我只是说,一个用例似乎是它能够发现糟糕的编码。我明白你的观点,但在这种情况下,代码并没有掩盖它只是不断变化的全局变量——这很糟糕,我认为这种方法根本不起作用。首先,它依赖于ln.split(),它只是根据空格字符进行拆分。如果代码包含行“x=1”(无空格),该怎么办?然后split()将找不到“x”。其次,这种方法不理解代码。如果“x”在一个字符串中怎么办?如果x是另一个对象的属性,即“something.x”,该怎么办?这些案件不应该被抓获,因为它们不涉及全球x。谢谢。这似乎是我应该使用的方法。你能详细解释一下“在范围方面不能正常工作”是什么意思吗?@user1804375我在回答中也回答了我,看起来它应该只在foo()中找到“y”。但是,答案很好。非常感谢。问一个后续问题:如何修改ast树以便重命名全局变量的实例,例如,使“x”在编译之前变成“a”,而“y”变成“b”?