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

I am trying to analyze some messy code, that happens to use global variables quite heavily within functions (I am trying to refactor the code so that functions only use local variables). Is there any way to detect global variables within a function?

For example:

def f(x):

x = x + 1

z = x + y

return z

Here the global variable is y since it isn't given as an argument, and neither is it created within the function.

I tried to detect global variables within the function using string parsing, but it was getting a bit messy; I was wondering if there was a better way to do this?

Edit: If anyone is interested this is the code I am using to detect global variables (based on kindall's answer and Paolo's answer to this question: 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 by default does not return output, so if you want to manipulate the output of dis as a string, you have to use the capture decorator written by Paolo and posted here: Capture stdout from a script in Python

解决方案

Inspect the bytecode.

from dis import dis

dis(f)

Result:

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

The global variables will have a LOAD_GLOBAL opcode instead of LOAD_FAST. (If the function changes any global variables, there will be STORE_GLOBAL opcodes as well.)

With a little work, you could even write a function that scans the bytecode of a function and returns a list of the global variables it uses. In fact:

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']

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值