2017-08-03 60 views
0

在我的代碼中,我需要檢測一個變量是否是一個函數,並對它執行一些操作。爲什麼functools.partial沒有被檢測爲types.FunctionType?

一切都進行得很順利,直到我現在用functools,突然產生一個局部功能我的一些測試失敗:

import types 
import functools 

def f(s): 
    print(s) 

l = lambda s: print(s) 

pf = functools.partial(f, 'Hello World') 
pl = functools.partial(l, 'Hello World') 
test_f = isinstance(f, types.FunctionType) # True 
test_l = isinstance(l, types.FunctionType) # True 
test_pf = isinstance(pf, types.FunctionType) # False 
test_pl = isinstance(pl, types.FunctionType) # False 

爲什麼會出現這些差異?這兩種變種都是可以調用的......更重要的是,如果我不能使用types.FunctionType,我怎麼能檢測出某個變量是否爲函數?

+2

爲什麼你需要檢查某些東西是否是明確的函數?檢查某些東西是否可以[(可調用的)](https://docs.python.org/3/library/functions.html#callable)是否足夠好? – mgilson

+0

*'types.FunctionType','types.LambdaType' - 由'lambda'表達式創建的用戶定義函數和函數的類型。* - 顯然不包含任何'partial'返回值。 – deceze

+0

@mgilson這是可能的,如果沒有其他解決方案,我並不完全反對它,但希望有 –

回答

3

functools.partial__call__方法,它說,在文檔:

返回一個新的partial對象,當所謂的將表現得像FUNC

(大膽強調加我)

我們可以在Python的REPL證實了這一點:

>>> from functools import partial 
>>> add_one = partial(sum, 1) 
>>> type(add_one) 
<class 'functools.partial'> 

一個Python相當於將是這樣的:

class Partial: 

    def __init__(self, func, *args, **kwargs): 
     self.func = func 
     self.args = args 
     self.kwargs = kwargs 

    def __call__(self, *args, **kwargs): 
     return self.func(*self.args, *args, **self.kwargs, **kwargs) 

所以它周圍產生函數的簡單包裝對象,和對象像這樣根本不是一個功能。 types.FunctionType只適用於實際功能。

什麼你要找的是檢查是否有物體調用一個方式,你可以使用內置的callable功能:

>>> callable(sum) 
True 
>>> callable(3) 
False 
>>> callable(functools.partial(sum, 1)) 
True 
+0

好的答案,但你確定它是這樣的對象嗎?該文檔聲稱這是一個函數:https://docs.python.org/3/library/functools.html –

+1

@OferSadan - 不,該文檔聲稱它與列出的函數相當。 – mgilson

0

在大多數情況下,你不需要知道是否有某個功能。通常,你所關心的是該對象是,可調用。爲了檢查這個,python有一個叫做callable的內建函數。

請注意,只是因爲callable返回True,這並不意味着調用該對象將成功。但是,對於調用函數,可以很容易地說:-)。


如果你真的只希望處理功能和partial對象,那麼你可以寫你的支票:

isinstance(obj, (types.FunctionType, functools.partial)) 

但這不是我的口味足夠的「鴨子」。

+0

'isinstance(obj,(types.FunctionType,functools.partial))'請不要,這只是乞求未來的錯誤 –