2017-03-03 89 views
-1

我無法弄清楚我做錯了什麼。看來我不能使用DIR()作爲缺省參數的函數的輸入如何使用dir()作爲函數內的默認參數

def print_all_vars(arg=dir()): 
    for i in arg: 
     print(i) 

foo=1 

如果我使用

print_all_vars() 

使輸出

__builtins__ 
__cached__ 
__doc__ 
__file__ 
__loader__ 
__name__ 
__package__ 
__spec__ 

print_all_vars(dir()) 

輸出

__builtins__ 
foo 
print_all_vars 
+5

默認參數中的表達式只執行一次*並與函數對象一起存儲。他們不是每個電話。您將看到模塊名稱空間(模塊中的全局變量函數被定義)。 –

+0

@ Lee88:* what * dir()* *你想反思什麼名字? –

+0

也許如果你解釋你正在努力完成的事情會更好。這聽起來像是我的XY問題。 –

回答

1

所以 - 一,什麼是要去 -

def語句行只運行一次,在首次進口(或在交互式提示符)包含的功能模塊 - 無論如何,任何用作默認參數值的表達式都會被單獨計算一次,其結果對象將保留爲該參數的默認值。

因此,您的dir()調用將被執行,並且包含您的示例函數的模塊名稱空間上的結果列表-a被保存。 (Python初學者最常見的相關錯誤是嘗試將空列表或字典([]{})作爲參數默認值:同一個列表或字典將在函數的生命週期中重用)。

這解釋了爲什麼您在輸出中看到一些值,如果您使用交互式提示(如__package____spec__)中的dir調用該值,則該值不會顯示出來。

現在,您真正的問題是:

...我其實是想創建一個模擬MATLAB的保存功能 來保存所有的現有的變量稍後可以 回憶外部文件 -

所以,即使你的dir()會懶洋洋地執行,當函數只被調用時,仍然會失敗:它仍然會從模塊檢索的變量名,其中功能被定義,而不是來電者。

做這件事的編碼模式是:

def print_all_vars(arg=None): 
    if arg is None: 
     arg = dir() 
    ... 

(這是強制執行的字典空列表作爲函數體中默認參數的最常用的方法)

但即使這樣,或者如果您將自己的變量名稱清單傳遞給該函數,那麼您仍然只有一個字符串列表 - 不需要您需要保存的Python對象。

而且 - 如果你想在默認情況下從調用者那裏檢索變量,你有一個與使用這個字符串列表相同的問題:你需要能夠訪問調用者代碼的名字空間,以便檢索那裏存在的變量名稱,然後檢索它們的內容以便保存。

在Python中知道「誰調用了你的函數」的方法是一件高級的事情,我甚至不確定它是保證在所有Python實現中工作 - 但它肯定會工作在最常見的(cPython ,Pypy,Jython)甚至一些被認爲較小的(比如Brython):

您可以撥打sys._getframe()來檢索當前正在執行的代碼的框架對象(也就是您的函數本身的代碼) - 並且此框架對象將會有一個f_back屬性,它指向您的函數的代碼的框架對象,其中被稱爲。框架對象在其側面引用分別作爲普通字典運行的代碼的全局變量和局部變量,分別爲f_globalsf_locals

您可以將它們「保存」和「恢復」,因爲您希望調用者代碼上的全局變量的內容 - 但無法使用純Python代碼更新局部變量。

所以,僅僅通過默認列表呼叫者代碼全局變量 - 你可以這樣做:

import sys 


def print_all_vars(arg=None): 
    if arg is None: 
     arg = list(sys.get_frame.f_back.f_globals.keys()) 
    print (arg) 

如果能夠妥善保存和恢復這些變量是另外一個問題 - 你可以在註釋中看到,您可以使用pickle來序列化很多Python對象 - 但調用者名稱空間將包含模塊名稱(如math np`等等),這些模塊名稱通常不會被醃製 - 因此您必須使用策略通過對所有檢索到的對象進行進一步的反省來檢測,註釋使用過的模塊並恢復它們。

無論如何,試驗這裏的信息應該讓你走上你想要的軌道。

相關問題