2010-08-04 17 views
2

我已經編寫了一個遠程Python調試器,我需要的功能之一是在斷點處停止時執行任意代碼。我的調試器中使用以下步驟執行從遠程調試器收到的代碼:原始局部範圍內的執行代碼

exec (compile(code, '<string>', 'single') , frame.f_globals, frame.f_locals) 

這在大多數情況下工作正常,但我注意到一對夫婦的問題。

  1. 賦值語句實際上並不適用於原始locals詞典。這可能是由於f_locals應該是隻讀的。

  2. 如果在類方法中停止,則訪問受保護的屬性(以雙下劃線開頭的名稱)不起作用。我假設這是由於Python在受保護的屬性上執行的名稱改變造成的。

所以我的問題是,是否有解決這些限制的方法?我能否讓Python認爲代碼是在該框架的實際本地範圍內執行的?

我正在使用CPython 2.7,我願意接受針對此版本的解決方案/破解。

回答

2

賦值語句實際上並不是 適用於原始當地人 字典。這可能是由於 這個事實,即f_locals應該是 是隻讀的。

不完全是,但該函數的字節碼不會看locals,使用相當簡單的,但重要的優化,其中局部變量是在一個簡單的數組,避免運行時查找。避免這種情況的唯一方法是編寫不同的代碼,例如,編寫不同的代碼。代碼以exec ''開頭,強制編譯器避免優化(在Python 2中;沒有辦法,在Python 3中)。如果您需要使用現有的字節碼,那麼您運氣不佳:有沒有方式來實現您的願望。

如果一個類的方法內停止, 訪問受保護的屬性(與雙下劃線開頭的名稱 )不 無法正常工作。我假設這是由於 由於Python對受保護的屬性執行 而導致的名稱損壞。

是的,所以這個問題確實允許一種變通方法:預先準備_Classname名字就模仿編譯器做什麼。請注意,雙下劃線前綴意味着私人保護將是一個下劃線(並會給你沒有麻煩)。私人名字專門用於避免名稱與子類綁定在一起的意外類(並且爲了這個目的而正常工作,儘管不是完美的,而不是其他任何東西;-)。

+0

不是我希望的答案,但謝謝澄清Alex。 – flashk 2010-08-04 18:35:34

0

我不知道我理解正確的話你,但exec確實與裏面的代碼分配填充locals參數:

>>> loc = {} 
>>> exec(compile('a=3', '<string>', 'single'), {}, loc) 
>>> loc 
{'a': 3} 

也許f_locals不允許寫入。

+0

根據我的經驗,f_locals是可寫的,但它似乎是原始locals()字典的副本。所以對其進行的任何更改都不會影響原始範圍。 – flashk 2010-08-04 16:56:24

0

執行任意代碼,而停在斷點......我可以誘使Python認爲代碼是在該框架的實際本地範圍內執行嗎?

Python調試器pdb允許這樣做。例如,假設您正在調試的文件tests/scopeTest.py,你必須在你的程序,其中變量尚未在程序本身聲明的下面一行:

print (NOT_DEFINED_IN_PROGRAM) 

,這樣運行的代碼python tests/scopeTest.py會導致在:

NameError: name 'NOT_DEFINED_IN_PROGRAM' is not defined 

現在你想,當在調試器,停止線來定義變量,並有計劃繼續執行,使用變量,如果它已經在節目中一直定義。換句話說,您希望在該範圍內實現更改,以便您可以繼續使用該更改永久性執行。它實際上是可能的:

$ python -m pdb tests/scopeTest.py 
> /home/user/tests/scopeTest.py(1)<module>() 
-> print (NOT_DEFINED_IN_PROGRAM) 
(Pdb) 'NOT_DEFINED_IN_PROGRAM' in locals() 
False 
(Pdb) NOT_DEFINED_IN_PROGRAM = 5 
(Pdb) 'NOT_DEFINED_IN_PROGRAM' in locals() 
True 
(Pdb) step 
5 

PDB在其default函數,該函數的等效執行此通過compileexec

code = compile(line + '\n', <stdin>, 'single') 
exec(code, self.curframe.f_globals, self.curframe_locals) 

其中self.curframe是一個特定的幀。現在,self.curframe_localsself.curframe.f_locals,因爲,作爲setup功能說:

# The f_locals dictionary is updated from the actual frame 
# locals whenever the .f_locals accessor is called, so we 
# cache it here to ensure that modifications are not overwritten. 
self.curframe_locals = self.curframe.f_locals 

希望幫助,併爲你的意思!

的是,即使是這樣,你應該想,例如替換方案方面的功能正在調試與猴子打補丁的版本

拿筆記,如:

newGlobals['abs'] = myCustomAbsFunction 
exec(code, newGlobals, locals) 

的範圍myCustomAbsFunction不會成爲用戶程序,但將成爲定義函數的上下文,這是調試器!這也有一種解決方法,但是由於沒有特別提出,所以現在留給讀者作爲練習。^__^