4

假设我有以下功能:

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

它工作正常。

为什么会这样:编译器不能正确区分变量和函数调用?

有什么办法吗?

4

5 回答 5

16

在 Python 中,函数是数据,而类型是动态的。这意味着以下行是有效的 Python:

def func(x):
    return x + 3

func = 3

func现在是一个int。func不再引用原始函数。最初是一个函数的事实func与将来可以分配给它的数据类型没有任何关系。(这就是“动态类型”的意思。)

因此,由于没有静态类型,并且“函数”是有效的数据类型,Python 解释器区分函数和同名引用的数据是没有意义的。因此,在给定的范围内,没有办法使用相同的非限定变量名来表示两个不同的东西。

在您的特定情况下,如果您的xplus1函数中的代码意味着什么,那将意味着“计算变量的值xplusy(x,1)并将该值分配给变量xplusy- 从而失去对函数 xplusy的引用。” 但是,在函数范围内,解释器不允许您对该范围之外的变量进行赋值,因此它假定通过编写赋值语句,您正在引入一个新的局部变量xplusy。但是,尚未定义局部变量,因此您调用它的尝试xplusy(x,1)失败了。全局定义的函数不作为后备调用,因为同样,您不能让两个非限定名称相同并指向同一范围内的不同数据。


另一个演示“在一个范围内不重复变量名”规则的示例(实际上,我只是在尝试构建此答案时使用提示符时才发现的):

>>> def f1():
...     a = xplusy(3,4)
...     xplusy = 5
...     print xplusy
...
>>> f1()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in f1
UnboundLocalError: local variable 'xplusy' referenced before assignment
>>> def f1():
...     a = xplusy(3,4)
...     print a
...
>>> f1()
7

这表明它确实是范围,而不是需要唯一名称的语句。


编辑:这是一个非常酷的帖子,解释了这个和其他范围相关的行为: http: //me.veekun.com/blog/2011/04/24/gotcha-python-scoping-closures/

于 2013-04-22T07:06:25.687 回答
3

在 python 中,函数是第一类对象,这意味着它与任何其他对象一样。

有关什么是“一流”对象的更多信息?

于 2013-04-22T06:53:50.867 回答
2

发生这种情况的原因是因为作为全局变量存在于您的范围内,除非您明确地说is xplusy,否则无法更改该变量。xplusyglobal

def xplusy(x,y):
    return x+y

def xplus1(x):
    global xplusy
    xplusy = xplusy(x,1)
    return xplusy

但是,这将xplusy引用 an或第一次返回的任何内容,这意味着在第一次之后它将抛出s。intfloatxplusyTypeError

更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)
于 2013-04-22T06:51:39.060 回答
1

在某些情况下,例如在回调中,您可以通过静态名称(funcName而不是funcName())来引用函数。因此,在 Python 中,变量名是为函数保留的。很像您如何使用存储在变量中的 LAMBDA 函数。

于 2013-04-22T06:52:09.763 回答
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变量将otherfunctionxplus1范围内引用。

xplus1(2)
>>> 2

结果是 2 * 1 而不是 2 + 1。小心分配。使用尽可能多的变量。

于 2013-04-22T07:00:47.740 回答