2014-07-26 30 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