2014-07-26 33 views
2

我正在做一個玩具Python typechecker,使用Python 3中的函數註釋特性來定義函數參數和返回值的類型,而且我似乎遇到了一個問題,檢查一個函數類型是否是另一個函數的子類型。以這兩個功能:給定一個函數的位置參數的名稱,可以確定該參數的位置?

def f(x: int, y: int) -> type(None): 
    pass 

def g(a: object, b: int) -> type(None): 
    pass 

我希望有我的代碼確定的g類型是f類型的亞型(因爲每個f的參數的類型的類型的子類型在g的參數列表中的相同索引處的參數,並且返回類型g是返回類型f的子類型)。然而,__annotations__場是一本字典:

f.__annotations__ == { 'x': int, 'y': int, 'return': type(None) } 

,這意味着它不向我提供有關參數排序,我想我需要的信息。是否有一種可靠的方法來確定xf的第一個參數,僅通過檢查運行屬性f

回答

5

是的,Python函數確實帶有這些信息。

最容易的就是使用inspect.getfullargspec()函數來提取這些信息,或者從Python 3.3開始,使用Signature objects

inspect.getfullargspec()返回值有.args屬性列出的參數順序:

>>> import inspect 
>>> def f(x: int, y: int) -> type(None): 
...  pass 
... 
>>> def g(a: object, b: int) -> type(None): 
...  pass 
... 
>>> inspect.getfullargspec(f) 
FullArgSpec(args=['x', 'y'], varargs=None, varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'NoneType'>}) 
>>> inspect.getfullargspec(f).args 
['x', 'y'] 
>>> inspect.getfullargspec(g).args 
['a', 'b'] 

註解也都會顯示:

>>> inspect.getfullargspec(f).annotations 
{'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'NoneType'>} 
>>> inspect.getfullargspec(g).annotations 
{'return': <class 'NoneType'>, 'a': <class 'object'>, 'b': <class 'int'>} 

簽名的對象是富裕還是:

>>> sig_f = inspect.signature(f) 
>>> sig_g = inspect.signature(g) 
>>> sig_f.parameters 
mappingproxy(OrderedDict([('x', <Parameter at 0x1031f1ea8 'x'>), ('y', <Parameter at 0x102e00228 'y'>)])) 
>>> sig_f.parameters['x'].annotation 
<class 'int'> 
>>> sig_g.parameters['b'].annotation 
<class 'int'> 
>>> sig_f.return_annotation == sig_g.return_annotation 
True 

我們在那裏Signature.parameters es一個有序的字典,讓您按照正確的順序比較參數。

+0

很棒,感謝您的快速響應!所以我不會讓我接受它,直到再過10分鐘,但這完全回答了我的問題。 – jcsmnt0