今天我发现了以下一段代码的奇怪行为:
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语句中使用的格式函数?
第二个是为什么它在函数外部调用时会有不同的行为(现在有预期的行为)?
答案 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")