按签名查询Python函数
怎样才能最好地记录或装饰你的Python函数或方法,以便你能轻松地根据函数的签名(比如参数数量、参数类型和返回类型)进行查询呢?
我在玩一个遗传编程的包,想要扩展它,让它能够动态地在表达式中替换一个函数,方法是随机从我模块中所有具有相同签名的函数中选择一个替换。
我在考虑自己写一个装饰器,这样我就可以做类似这样的事情:
@validate(args=((int, range(1,10), (float, range(1,10)), (bool,)), returns=(int,range(-10,10))
def myfunc(a, b, c):
result = do_stuff
return result
然后我可以通过类似这样的方式查询相似的函数:
similar_functions = find_functions(like=myfunc)
有没有什么标准的工具或库可以做到这一点呢?
3 个回答
动态地用模块中所有具有相同参数的函数随机替换一个表达式中的函数。
只需这样做。
all_functions_of_some_sig = [
myfunc, myfunc2, myotherfunc, ...
]
这并不难。而且这样做更有可能成功,因为任何筛选或匹配都是由函数的设计者来完成的。
这可能更简单
def myfunc( a, b, c ):
return something
myfunc.args= ((int, range(1,10), (float, range(1,10)), (bool,))
myfunc.returns= (int,range(-10,10))
patterns= collections.defaultdict( list )
for f in __all__:
patterns[f.args,f.returns]= f
这就是你想要的吗?
你只需要确保 __all__
列出了所有相关的函数。这并不难,而且通常是包含成千上万函数的模块所期望的。
为了保持“我们都是成年人”的心态,为什么你需要确保指定的类型真的被遵守呢?你知道这个函数的签名应该是什么样的,所以只要给每个函数加上一个装饰器,然后把这些标签存储在一个字典里就行了。
>>> import collections
>>> tags = collections.defaultdict(set)
>>>
>>> def tag(tag):
... def decorator(func):
... tags[tag].add(func)
... func.tag = tag
... return func
... return decorator
...
>>> @tag("foo")
... def a(): pass
...
>>> @tag("foo")
... def b(): pass
...
>>> tags['foo']
{<function b at 0x0000000002BF2448>, <function a at 0x0000000002BD5A48>}
similar
是很简单的:
def similar(func):
return signatures[func.sig]
你可以使用 inspect
来获取函数的参数列表。这包括默认值,但当然无法提供类型信息,因为函数的定义里没有这些信息。
像你展示的装饰器在 Python 2.x 中似乎是获取类型信息的最佳解决方案。不过我可能会让它的语法看起来少一些括号:
@validate(a=(int, 1, 10), b=(float, 1, 10), c=bool, returns=(int, -10, 10))
def foo(a, b, c): ...
如果你的装饰器能够检查函数的参数列表,并确保它与装饰器的参数匹配,那么你可能会发现明显的错误。如果你不打算添加验证代码,它不需要修改实际的函数。
需要注意的是,*arg
和 **kwarg
需要特别处理:这些的类型信息更难提供。我也不知道 f1(int, int, int)
和 f2(int, *ints)
有多相似,更不用说 f3(int, **kwargs)
了。