python 2.7.3 中函数和局部变量名称相同的行为不一致

Inconsistent behavior in python 2.7.3 with same name of function and local variable

今天我发现以下代码有一些奇怪的行为:

if (arg == 0):
   # some local variable
   format = ""
   ret = format + arg
else:
   # bultin format function
   ret = format(arg, "#x")

print ret

它起着内外不同的作用。 使用此代码:

import sys

def foo(arg):
   if (arg == 0):
      # some local variable
      format = ""
      ret = format + "0"
   else:
      # bultin format function
      ret = format(arg, "#x")

   print ret


arg = int(sys.argv[1])


print "Outside function:"
if (arg == 0):
   # some local variable
   format = ""
   ret = format + "0"
else:
   # bultin format function
   ret = format(arg, "#x")

print ret


print "Foo call:"
foo(arg)

我得到以下调用输出:python format.py 1

Outside function:
0x1
Foo call:
Traceback (most recent call last):
  File "format.py", line 31, in <module>
     foo(arg)
  File "format.py", line 10, in foo
    ret = format(arg, "#x")

第一个问题是为什么if语句下的一个局部变量隐藏了else语句中使用的格式化函数?

第二个是为什么在函数外部调用时它的行为不同(现在具有预期的行为)?

Python 区分全局变量和局部变量;在函数外,format 是全局的,在函数内,format 是局部的 因为你给它赋值(如果你从未在函数中的任何地方绑定名称函数,它将被视为全局函数)。您不能同时将名称视为全局名称和本地名称。

if在这里无关紧要;名称可见性适用于 整个范围 if 没有引入新的作用域,只有函数引入了。所以在函数中,format 是局部名称,永远不能作为全局名称查找,无论 if 块如何。

你的代码在函数之外工作,因为已经有一个名为 format 的全局变量;它是一个内置函数。如果 args == 0 为真,您的代码将只工作 一次 因为之后它会将全局变量反弹为字符串,并且以后对 format() 的调用将失败。

在函数内部,format 现在是本地的,如果 args != 0 则永远不会设置;这里的赋值由 if 保护并不重要,它要么是 always 本地的,要么是 always 全局的,因为这是在编译时确定的。

您可以通过不在此处重载名称 format 来轻松避免此问题。您不想一开始就意外地屏蔽名称 format ,因为这会破坏其他想要使用 format() 函数的代码。对于您的具体示例,完全删除 format 的使用是微不足道的:

def foo(arg):
    if (arg == 0):
        ret = "0"
    else:
        # bultin format function
        ret = format(arg, "#x")

   print ret

您甚至可以根据 args 的值更改格式配置:

def foo(arg):
    return format(arg, "#x" if args else "d")