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

时间:2015-04-02 13:06:23

标签: python python-2.7 scope

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

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语句中使用的格式函数?

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

1 个答案:

答案 0 :(得分:3)

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

if在这里并不重要;名称可见性适用于整个范围; if不会引入新范围,只有函数才会引入。因此,在函数中,format是一个本地名称,无论if块是什么,都不能将其视为全局名称。

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

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

您可以通过此处不重载名称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")