2017-01-23 99 views
2

我試圖做嵌套函數(函數內的函數)的單元測試,我使用代碼(「嵌套」是函數名稱)從下面的鏈接將提供關閉並返回可從測試中調用的有效函數。它適用於簡單的功能。我試圖讓它適用於遞歸函數。獲取嵌套函數的函數的函數與遞歸

舉一個例子: 我想獲得一個「innerfunction」的有效函數,它在co_freevars中有一個條目作爲「innerfunction」。

我想獲得一個函數(函數類型我相信)「innerfunction」作爲一個可調用的。爲了得到這個,我需要用一個FunctionType爲「innerfunction」調用FunctionType。這成爲遞歸的「依賴」。我怎樣才能解決這種相關性爲「倒閉潮」

函數發送參數

def toplevelfunction(): 
    def innerfunction(a): 
     print ('val of a is ', a) 
     if a > 0: 
      innerfunction(a -1) 
    innerfunction(10) 

原始代碼,我使用:

def freeVar(val): 
    def nested(): 
    return val 
    return nested.__closure__[0] 

codeAttribute = '__code__' if sys.version_info[0] == 3 else 'func_code' 

def nested(outer, innerName, **freeVars): 
    if isinstance(outer, (types.FunctionType, types.MethodType)): 
    outer = outer.__getattribute__(codeAttribute) 
    for const in outer.co_consts: 
    if isinstance(const, types.CodeType) and const.co_name == innerName: 
     return types.FunctionType(const, globals(), None, None, tuple(
      freeVar(freeVars[name]) for name in const.co_freevars)) 

https://code.activestate.com/recipes/580716-unit-testing-nested-functions/

如何加入支持如下的關閉工作:

fu NC =嵌套(toplevelfunction,「innerfunction」)

FUNC(5)

將返回錯誤不需要長度的閉合1. 添加閉合參照「常量」顯示出來,這是CODETYPE而不是函數類型。 在閱讀文檔後,添加一個閉包值來引用它自己似乎很棘手。

找我幹什麼innerfunction爲:

{code} <code object innerfunction at 0x104b9bc00, file "/<filedirectory>/handle_results.py", line 44> 
co_argcount = {int} 1 
co_cellvars = {tuple} <class 'tuple'>:() 
co_code = {bytes} b"t\x00\x00d\x01\x00|\x00\x00\x83\x02\x00\x01|\x00\x00d\x02\x00k\x04\x00r'\x00\x88\x00\x00|\x00\x00d\x03\x00\x18\x83\x01\x00\x01d\x00\x00S" 
co_consts = {tuple} <class 'tuple'>: (None, 'val of a is ', 0, 1) 
co_filename = {str} '/<fildirectory>/handle_results.py' 
co_firstlineno = {int} 44 
co_flags = {int} 19 
co_freevars = {tuple} <class 'tuple'>: ('innerfunction ',) 
co_kwonlyargcount = {int} 0 
co_lnotab = {bytes} b'\x00\x01\r\x01\x0c\x01' 
co_name = {str} 'innerfunction ' 
co_names = {tuple} <class 'tuple'>: ('print',) 
co_nlocals = {int} 1 
co_stacksize = {int} 3 
co_varnames = {tuple} <class 'tuple'>: ('a',) 
+2

至少,你錯過了導致'toplevelfunction'返回內部函數的返回語句,而不是返回'None'並放棄它創建的函數。 – chepner

+0

你能詳細說一下嗎?我上面編輯指定我如何使用測試「嵌套」。 – MyDevMallik

+0

'toplevelfunction'沒有做任何有用的事情。你沒有顯式的'return'語句,所以它隱含地返回'None'。 「頂層功能」退出後,不存在對「內部功能」的引用。 (即使你將'return innerfunction'添加到'toplevelfunction',它也不是一個非常有趣的閉包,因爲'toplevelfunction'中沒有其他局部變量可以關閉。) – chepner

回答

0

謝謝你暗示我對我的ActiveState食譜這個限制,你在你的問題掛!

您試圖單元測試一個本地遞歸函數;我對這個小例子看起來是這樣的:

def f(x): 
    def fac(n): 
    return fac(n-1) * n if n > 1 else 1 
    print "Faculty of", x, "is", fac(x) 

因此,在一個單元測試,你要測試的內部函數fac()。簡單地將我的食譜會導致這個錯誤:

nestedFac = nested(f, 'fac') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 7, in nested 
    File "<stdin>", line 7, in <genexpr> 
KeyError: 'fac' 

這是因爲fac是內部函數中使用的標識符,你必須指定每個標識的內部函數中使用的值。可贖回標識符也不例外:

nestedFac = nested(f, 'fac', fac=None) 

這臺fac的值None和調用nested不會再失敗。

遺憾的是,得到的函數將嘗試調用None(...),當你把它叫做:

nestedFac(5) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 3, in fac 
TypeError: 'NoneType' object is not callable 

您將需要本身傳遞給函數的值fac避免這種情況。不幸的是,當你撥打nested()時,你還沒有。重複包裝可以做這樣的:

nestedFac = nested(f, 'fac', fac=None) 
nestedFac = nested(f, 'fac', fac=nestedFac) 
nestedFac = nested(f, 'fac', fac=nestedFac) 
nestedFac = nested(f, 'fac', fac=nestedFac) 

這將限制你的遞歸深度給你施加包裝數量:

nestedFac(2) 
2 
nestedFac(3) 
6 
nestedFac(4) 
24 
nestedFac(5) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 3, in fac 
    File "<stdin>", line 3, in fac 
    File "<stdin>", line 3, in fac 
    File "<stdin>", line 3, in fac 
TypeError: 'NoneType' object is not callable 

爲了避免這種情況,你可以通過一個本地功能代理:

def q(*args, **kwargs): 
    return nestedFac(*args, **kwargs) 
nestedFac = nested(f, 'fac', fac=q) 

或者作爲lambda

nestedFac = nested(f, 'fac', fac=lambda *args, **kwargs: 
    nestedFac(*args, **kwargs)) 

或者只是一個參數的特殊情況:

nestedFac = nested(f, 'fac', fac=lambda n: nestedFac(n)) 

的擴展nested()配方,可自動完成,這將是更好的方法,雖然。隨意分享食譜,並添加這方面! :-)