python - 检测 python 函数中的所有全局变量?

标签 python function global-variables

我正在尝试分析一些困惑的代码,这些代码恰好在函数中大量使用全局变量(我正在尝试重构代码,以便函数仅使用局部变量)。有什么方法可以检测函数内的全局变量吗?

例如:

def f(x):
    x = x + 1
    z = x + y
    return z

这里的全局变量是y,因为它不是作为参数给出的,也不是在函数中创建的。

我尝试使用字符串解析来检测函数内的全局变量,但它变得有点困惑;我想知道是否有更好的方法来做到这一点?

编辑:如果有人感兴趣,这是我用来检测全局变量的代码(基于 kindall 的回答和 Paolo 对这个问题的回答:Capture stdout from a script in Python):

from dis import dis

def capture(f):
    """
    Decorator to capture standard output
    """
    def captured(*args, **kwargs):
        import sys
        from cStringIO import StringIO

        # setup the environment
        backup = sys.stdout

        try:
            sys.stdout = StringIO()     # capture output
            f(*args, **kwargs)
            out = sys.stdout.getvalue() # release output
        finally:
            sys.stdout.close()  # close the stream 
            sys.stdout = backup # restore original stdout

        return out # captured output wrapped in a string

    return captured

def return_globals(f):
    """
    Prints all of the global variables in function f
    """
    x = dis_(f)
    for i in x.splitlines():
        if "LOAD_GLOBAL" in i:
            print i

dis_ = capture(dis)

dis_(f)

dis 默认不返回输出,所以如果你想将 dis 的输出作为字符串操作,你必须使用 Paolo 和发布在这里:Capture stdout from a script in Python

最佳答案

检查字节码。

from dis import dis
dis(f)

结果:

  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               1 (1)
              6 BINARY_ADD
              7 STORE_FAST               0 (x)

  3          10 LOAD_FAST                0 (x)
             13 LOAD_GLOBAL              0 (y)
             16 BINARY_ADD
             17 STORE_FAST               1 (z)

  4          20 LOAD_FAST                1 (z)
             23 RETURN_VALUE

全局变量将有一个 LOAD_GLOBAL 操作码而不是 LOAD_FAST。 (如果函数更改任何全局变量,也会有 STORE_GLOBAL 操作码。)

通过一些工作,您甚至可以编写一个函数来扫描函数的字节码并返回它使用的全局变量列表。事实上:

from dis import HAVE_ARGUMENT, opmap

def getglobals(func):
    GLOBAL_OPS = opmap["LOAD_GLOBAL"], opmap["STORE_GLOBAL"]
    EXTENDED_ARG = opmap["EXTENDED_ARG"]

    func = getattr(func, "im_func", func)
    code = func.func_code
    names = code.co_names

    op = (ord(c) for c in code.co_code)
    globs = set()
    extarg = 0

    for c in op:
        if c in GLOBAL_OPS:
            globs.add(names[next(op) + next(op) * 256 + extarg])
        elif c == EXTENDED_ARG:
            extarg = (next(op) + next(op) * 256) * 65536
            continue
        elif c >= HAVE_ARGUMENT:
            next(op)
            next(op)

        extarg = 0

    return sorted(globs)

print getglobals(f)               # ['y']

关于python - 检测 python 函数中的所有全局变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33160744/

相关文章:

python - keras model.predict_generator() 未返回正确的实例数

python - 如何在 Python 中解析模板化字符串?

python - 对列表列表求和以获得求和列表 Python

java - 从字符串到整数函数

Python 全局变量/范围混淆

全局变量的javascript提升

python - 在线程中运行 flask-socketio

python - 在 bool 列表中获取 True 值的索引

c++ - 我可以禁止临时对象作为参数吗?

javascript - 无法在全局变量中存储值