2015-04-02 22 views
0

今天,我發現下面的代碼段的一些怪異的行爲:不一致的行爲在Python 2.7.3與功能相同的名稱和局部變量

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) 

我獲得以下的輸出:蟒蛇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語句隱藏格式功能下的局部變量在其他語句中使用?

第二個原因是它在行爲函數外面調用時爲什麼會有不同的行爲(現在和預期行爲一樣)?

+0

使用[''' str.format()'''](https://docs.python.org/2/library/stdtypes.html#str.format)而不是['''format()'''](https:// docs.python.org/2/library/string.html#string.Formatter.format)。 – pzp 2015-04-02 13:22:36

+1

無論如何,創建一個與內置函數具有相同名稱的變量是不好的做法;一個人不應該這樣做。但是如果你真的想知道它爲什麼會發生,馬丁的答案是一個非常好的解釋。 – pzp 2015-04-02 13:31:45

回答

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") 
+0

@woockashek:但這意味着編譯器檢測到它是本地的。根據動態選擇,您不能將其視爲全球和本地。 – 2015-04-02 13:20:32

+0

我不明白你的解釋。 我分配一個值格式只在if的範圍內。 我在else語句中添加了'print locals()',並且只有'args'變量,所以全局'format()'函數不應該被局部變量隱藏。 此外,您可以刪除函數外部的調用,因此刪除對全局變量的任何賦值並且行爲仍然相同。 – woockashek 2015-04-02 13:23:27

+0

@woockashek:這就是我所說的; 'format'不能被視爲一個全局的,** ever **,因爲你的函數**可能**將它用作本地的。在Python中,這意味着它總是**是本地函數。 – 2015-04-02 13:26:34

相關問題