全局名称'p1'未定义
我有一个函数里面又定义了一个函数(见下面的代码)。
当我运行 >>> pd = distrib(10,listAll) 的时候,我得到了这个结果(注意行号是我文件里的行号,而不是下面示例中的行号)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "transportOpt.py", line 78, in distrib
N = NN(0,t1)
File "transportOpt.py", line 48, in NN
print(p1,p2)
NameError: global name 'p1' is not defined
这是函数的具体内容
def distrib(Nm,lf):
l = len(lf)
pd = {}# the output dictionary distribution
sumpd = 0# the total number of samples
p1=0
p2=0
buf=[lf[0]]
def NN(a,b):
global p1,p2
print(p1,p2)
y = max(a,b)
x = min(a,b)
if y>p2:
for j in range(p2-p1+1,y-p1+1):
buf.append(buf[j-1]+lf[j])
p2 = y
if x>p1:
for j in range(0,x-p1):
buf.pull(j)
p1 = x
return buf[b-p1]-buf[a-p1]
def UpdateDistrib(a,b):
global sumpd
tao = t1-t0
if tao < 0:
print('UpdateDistrib: t1<t0: mistake')
if tao == 0:
tao = 1
CurrentCount = pd.get(tao,0)
pd[tao] = CurrentCount + 1.
sumpd = sumpd + 1.
def normdistrib():
for i in pd.keys():
num = pd[i]
pd[i] = num/sumpd
for t1 in range(l):
N = NN(0,t1)
if N>Nm:
UpdateDistrib(0,t1)
break
if t1==l-1 and N<=Nm:
normdistrib()
return pd
for t0 in range(1,l):
N = NN(t0,t1)
if N<=Nm:
if t1==l-1:
normdistrib()
return pd
r = range(t1+1,l)
for t1 in r:
N = NN(t0,t1)
if N>Nm:
UpdateDistrib(t0,t1)
break
else:
UpdateDistrib(t0,t1)
normdistrib()
return pd
出什么问题了?我是不是用“global”用错了?
3 个回答
1
你需要在函数 'distrib(Nm,lf):' 之外定义 p1 和 p2。全局函数是用来改变那些在原始函数外部的变量值的,而不是用来把它们引入到子函数中的。
p1 = 0
p2 = 0
def distrib(Nm,lf):
l = len(lf)
pd = {}# the output dictionary distribution
sumpd = 0# the total number of samples
buf=[lf[0]]
def NN(a,b):
global p1,p2
print p1,p2
1
你有没有在 distrib 函数外面定义 p1 呢?这可能就是你的问题,因为 p1 和 p2 仍然在 distrib 函数中被使用,它们是“封闭”的,Python 会知道该操作哪些变量。完全去掉 global 声明,应该就能正常工作了。
关于作用域的更多信息:Python 作用域规则的简要说明?
注意 LEGB 规则:局部(Local)、封闭(Enclosed)、全局(Global)、内置(Built-in)。
3
也许你认为 global p1
是让名字 p1
指向之前定义的变量 p1=0
。其实并不是这样,因为之前的变量并不是全局的,它是局部的,只在函数 distrib
内有效。
在定义嵌套函数时,你不需要使用 global
来引用外部变量。不过,在 Python 2.7 中,你不能通过嵌套函数去给外部变量赋值。要做到这一点,你需要使用 nonlocal
,而这个功能只在 Python 3.0 及以上版本中才有。因为在嵌套函数中对 p1
进行赋值,会导致这个名字无法指向外部函数中的 p1
,而使用 global
也没有用。