2015-06-19 119 views
2

我試圖寫一個函數調試裝飾器將着眼於內的字符串:解析蟒蛇作爲裝飾

def foo(baz): 
    bar = 1 
    bar = 2 
    return bar 

,並換到:

def foo(baz): 
    bar = 1 
    print 'bar: {}'.format(bar) 
    bar = 2 
    print 'bar: {}'.format(bar) 
    return bar 

我需要與打函數作爲文本來抓取「\ w +(?= \ s * [=])」,但不知道如何訪問它。我有一個裝飾,我從一個可行的博客修改,但我只是想將其更改爲:

class decorator_string_check(object): 

    def __init__(self, func): 
     self.func = func 
     wraps(func)(self) 

    def __call__(self, *args, **kwargs): 
     print dir(self.func) 
     print dir(self.func.__code__) 
     print self.func.__code__.__str__() 
     ret = self.func(*args, **kwargs) 
     return ret 

@decorator_string_check 
def fake(x): 
    y = 6 
    y = x 
    return y 

y = fake(9) 

和我得到的價值nothinng,即:

['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name'] 
['__class__', '__cmp__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames'] 
<code object fake at 0x7f98b8b1d030, file "./logging.py", line 48> 

如何與實際工作「func」文本,運行正則表達式並找到我需要的裝飾類對象中的東西?謝謝

回答

6

首先,我建議你做做這樣的事情。很難獲得有效的代碼,並且很難製作正確的版本。

除了我真的不知道你想要做什麼。這個裝飾器是否應該在每個作業後添加一個print聲明並顯示更新後的值?或只跟蹤給定的變量子集?

這就是說,獲得的一些源代碼,你可以使用inspect模塊特別是getsource功能:

In [1]: def test(): 
    ...:  a = 1 
    ...:  b = 2 
    ...:  

In [2]: import inspect 

In [3]: inspect.getsource(test) 
Out[3]: 'def test():\n a = 1\n b = 2\n' 
In [4]: print(inspect.getsource(test)) 
def test(): 
    a = 1 
    b = 2 

您可以修改,並根據需要檢查源代碼,並最終compile()新中源碼。

然而要注意:

  • 你必須修改源代碼時要小心,因爲很容易就可以創建語法無效的代碼(認爲:多表情等)
  • 編譯您希望在在與原始函數相同的範圍內進行編譯。 inspect模塊有一些函數可以讓你獲得調用裝飾器的堆棧,你可以從那裏獲取環境。閱讀here關於如何處理堆棧。
  • 源代碼可能不可用。代碼可以用字節碼編譯,原始文件可能會被刪除。在這種情況下,getsource只會引發OSError

更「理智」的解決辦法是看看源代碼,但在字節碼。您可以使用dis模塊執行此操作。您可以嘗試查看變量的值何時更改並插入一些將打印該變量的字節碼。

注意,dis模塊被大大python3.4 +與Python的早期版本中這可能將是很難提高,所以。

在嘗試此操作之前,您應該閱讀Python bytecode hacks, gotos revisited之類的文章。他們給你一個關於如何查看字節碼並使用它的想法。

這可能是安全的(例如,即使源文件不在計算機上存在的字節碼仍然可以訪問),但我還是覺得你心裏有什麼不做一件好事,除了作爲練習。


由於jsbueno指出,做你想做的(即蟒蛇調試器)的正確方法是使用sys.settrace

該函數允許您設置一個跟蹤函數,該函數將針對每個「代碼」執行。該函數將知道函數何時被調用,輸入了新的塊等。它允許您訪問將要執行代碼的幀,因此您應該能夠找到您感興趣的值。

您應該檢查lnotab_notes.txt文件以瞭解作爲該函數參數提供的數據如何映射到源代碼位置以瞭解何時執行分配。

當我有時間(可能下週結束)時,我會嘗試基於這種方法來實現一些東西來演示它。

+1

其實都一個理智的解決方案(不只是一個「更理智」)是使用Python調試工具-with'sys.settrace',並有效地編寫自定義調試器,將每行後局部變量的值進行比較,並打印不同的內容 - 在裝飾代碼的持續時間內提供一個能夠提供'settrace'的裝飾器並不困難。 – jsbueno

+2

@jsbueno你說得對。我不知道這件事,它*看起來是做這種事的唯一正確方式。我已將它添加到我的答案中。 – Bakuriu

+0

@Bakuriu doumo arigatou gozaimasu ... anata wa watashi yori mo kashikoku miemasu :) 我想跟蹤所有/每個變量的分配,只是爲了確切知道變量在那個時間點。這樣我可以裝飾一些不起作用的東西,而不是1238234打印語句方法。我相信整個世界都可以使用我們的裝飾器 – codyc4321