假设我有以下功能:
def xplusy(x, y):
return x+y
def xplus1(x):
xplusy = xplusy(x, 1)
return xplusy
现在,如果我调用a = xplus1(4)
,则会抛出以下错误:
UnboundLocalError: local variable 'xplusy' referenced before assignment
错误是因为命名冲突,如果我重新定义xplus1
如下:
def xplus1(x):
s = xplusy(x, 1)
return s
它工作正常。
为什么会这样:无法正确区分变量和函数调用?
有什么方法吗?
答案 0 :(得分:13)
在Python中,函数是数据,键入是动态的。这意味着以下行是有效的Python:
def func(x):
return x + 3
func = 3
func
现在是一个int。不再引用原始函数func
。 func
最初是一个函数的事实与将来可以分配给它的数据类型无关。 (这就是“动态打字”的含义。)
因此,由于没有静态类型,并且“function”是有效的数据类型,因此Python解释器区分函数和同名引用的数据是没有意义的。因此,在给定的范围内,没有办法使用相同的非限定变量名来表示两种不同的东西。
在您的特定情况下,如果xplus1
函数中的代码含有任何内容,则表示“计算xplusy(x,1)
的值并将值赋给变量{ {1}} - 从而失去了对功能 xplusy
的引用。“但是,在函数范围内,解释器不允许您对该范围之外的变量进行赋值,因此它假定通过编写赋值语句,您将引入新的局部变量xplusy
。但是,本地变量尚未定义,因此您尝试调用它xplusy
失败。全局定义的函数不会被称为回退,因为同样,您不能将两个非限定名称相同并指向同一范围内的不同数据。
另一个例子展示了“在一个范围内没有重复的变量名称”规则(我实际上只是在尝试构建这个答案的过程中玩弄提示时才发现):
xplusy(x,1)
这表明它确实是范围,而不是声明需要唯一名称。
编辑:这是一篇非常酷的帖子,解释了这个和其他与范围相关的行为:http://me.veekun.com/blog/2011/04/24/gotcha-python-scoping-closures/
答案 1 :(得分:3)
在python函数中是第一类对象,它意味着它与任何其他对象一样。
的更多信息答案 2 :(得分:1)
发生这种情况的原因是因为xplusy
作为全局变量存在于您的范围内,除非您明确指出xplusy
为global
,否则无法更改。
def xplusy(x,y):
return x+y
def xplus1(x):
global xplusy
xplusy = xplusy(x,1)
return xplusy
但是,这会使xplusy
引用int
,float
或第一次返回的xplusy
,这意味着它会在第一次投掷TypeError
之后1}} S上。
更多的pythonic方式很可能是
def xplus1(x):
return xplusy(x,1)
或使用functools
模块:
from functools import partial
xplus1 = partial(xplusy,y=1) #since you wanted to override y with 1
如果你不关心哪个参数被覆盖,你可以简单地做
xplus1 = partial(xplusy,1)
答案 3 :(得分:1)
有些情况,例如回调,您通过静态名称(funcName
而不是funcName()
)引用功能。因此在Python中,变量名是为函数保留的。很像你如何使用存储在变量中的LAMBDA函数。
答案 4 :(得分:1)
在Python中,xplusy
可以引用任何内容。你可以这样做:
def xplusy(x, y):
return x+y
def otherfunction(x, y):
return x*y
def xplus1(x):
xplusy = otherfunction
return xplusy(x, 1)
xplusy
变量将引用otherfunction
范围内的xplus1
。
xplus1(2)
>>> 2
结果是2 * 1而不是2 + 1.注意分配。使用尽可能多的变量。