2014-10-06 28 views
2

使用Ubuntu 14.04提供的Python 2.7.6。Python:檢查globals()中是否存在變量使其在本地上下文中不可見

我有一些函數引用由調用者定義的變量。我想要一種方法來查找調用者是否設置了變量(如果他們沒有,我會在本地設置一個默認值),所以我在StackOverflow上找到了this answer

我遇到的問題是檢查變量的存在使其不可見/不存在以下代碼。

爲方便調查此事的人員,下面的代碼塊應該可以直接剪切粘貼到系統上的文件進行測試。

#!/usr/bin/env python 

# Tested on Python 2.7.6 from Ubuntu 14.04. 

def calledfunction(): 

    print globals() 
    print 
    print locals() 
    print 

    # Try commenting the next five lines out. While they're here, the variable 
    # becomes invisible to the print statement below. 
    if not 'globalvar' in globals(): 
    globalvar = "created within the function" 
    print "assigning variable locally" 
    else: 
    print "variable assigned globally" 
    # global globalvar 
    # If you uncomment the above line, the variable is visible, but Python 
    # prints a syntax warning. 

    print 
    print globals() 
    print 
    print locals() 
    print 

    print "the variable 'globalvar' is:", globalvar 
    print 

# ----------------- 

print "calling function before the variable is defined" 
print 
calledfunction() 

globalvar = "created outside the function" 

print "calling function after the variable is defined" 
print 
calledfunction() 

我的期望是,在全局「變量」()試驗不應導致變量從print語句它後面的可見性消失。我的期望不正確嗎? (Python似乎認爲我不是)

+0

我對你想做什麼感到困惑。您定義的函數會感知作爲函數定義模塊一部分的全局變量。也就是說,您控制的模塊。因此,爲什麼不只是用合理的默認值初始化全局變量? – Dunes 2014-10-06 19:27:49

+0

@Dunes:函數並不總是在我控制的模塊中。它是庫的一部分,將被導入到其他代碼中,我可能會或可能不會控制它。 – 2014-10-06 20:41:49

+0

導入函數的全局變量是它在其中定義的模塊的全局變量。將其導入到其他模塊不會改變它。 – Dunes 2014-10-06 21:07:31

回答

2

請注意,當你開始像這樣動態檢查globals時,人們開始懷疑......這樣說,這裏有一個工作版本的代碼,只要你工作只從全局變量中「讀取」。

def calledfunction(): 
    default_local = 'some default' 
    var = globalvar if 'globalvar' in globals() else default_local 
    print var 

# ----------------- 

print "calling function before the variable is defined" 
print 
calledfunction() 

globalvar = "created outside the function" 

print "calling function after the variable is defined" 
print 
calledfunction() 

注意,一個函數中,變量名是全局或它的本地(和python3.x增加nonlocal的一羣)。但是,變量名稱不能爲global或本地,具體取決於函數的調用方式。

一個更好的方式就是使用關鍵字參數:當您要創建新的可變對象這樣

def calledfunction(var="Created within the function"): 
    print var 

calledfunction() # Created within the function 
calledfunction(var="Created by the caller") # Created by the caller 

有一些陷阱,但他們well known and documented with work-arounds

+0

在你的例子中,如果一個不存在的話,你不要創建一個名爲'globalvar'的全局變量。例如。 'del globalvar; calledfunction(); globals()中的「globalvar」評估爲true。 – Dunes 2014-10-06 19:08:17

+0

@Dunes - 已更新。 – mgilson 2014-10-06 19:13:52

+0

在測試工作之前增加額外**全局[varname] **。 (雖然我有這樣的鬆散變量的數量,但把它們放在通話中會讓一團糟。) – 2014-10-06 19:17:41

1

你在你的功能分配給globalvar(在該名稱未在globals()發現的情況。因此它是局部的功能。

您可以通過將該聲明變量全球提前在某處你的函數(通常在開頭):

global globalvar 

但是如果你需要看被調用函數中定義的變量,你可能做錯了什麼功能應該與你擦肩而過,你需要明確的數據。

1

據我瞭解,你有你的代碼設置類似如下:

library.py

def function(): 
    default_local = "local" 
    var = globalvar if 'globalvar' in globals() else default_local 
    print(var) 

if __name__ == "__main__": 
    globalvar = "main" 
    function() # prints "main" 

user.py

from library import function 

function() # prints "local" 
globalvar = "user" 
function() # prints "local" 
import library 
library.globalvar = "user" 
function() # prints "user" 

爲什麼不寫你的庫如下面的並用奇怪的全球查找爲您省去很多麻煩。

new_library.py

globalvar = "main" if __name__ == "__main__" else "imported" 

def function(): 
    print(globalvar) 

if __name__ == "__main__": 
    function() # prints "main" 

user.py將現在打印 「進口」 兩次,然後選擇 「用戶」。

+0

我使用了與上一個代碼塊相似的測試來觸發包裝命令行功能的主代碼。我很少使用「from x import y」表單,因爲我喜歡在導入時使用library_name.function()表單來避免名稱空間衝突。可能有些時候這些'全局'變量會由導入它們的代碼來設置,我只是不希望導入它的任何東西被設置爲'大多數'不會有這種需要。 – 2014-10-07 02:57:09

+0

通過使用「from」導入,我只是試圖說明該函數總是在它定義的模塊的上下文中執行。我還試圖證明您應該將全局變量的初始值設置爲你的本地變量。這樣,全球總是存在,因此你不需要測試它是否存在。但是,如果模塊作爲主模塊運行,或者庫的用戶想要設置不同的值,則可以更改它。 – Dunes 2014-10-08 10:14:34

相關問題