python中的冲突变量和函数名称

时间:2013-04-22 06:46:55

标签: python

假设我有以下功能:

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

它工作正常。

为什么会这样:无法正确区分变量和函数调用?

有什么方法吗?

5 个答案:

答案 0 :(得分:13)

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

def func(x):
    return x + 3

func = 3

func现在是一个int。不再引用原始函数funcfunc最初是一个函数的事实与将来可以分配给它的数据类型无关。 (这就是“动态打字”的含义。)

因此,由于没有静态类型,并且“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函数中是第一类对象,它意味着它与任何其他对象一样。

有关What are “first class” objects?

的更多信息

答案 2 :(得分:1)

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

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

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

但是,这会使xplusy引用intfloat或第一次返回的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.注意分配。使用尽可能多的变量。