有没有可能检查两个python函数是否可以互换?例如,如果我有
def foo(a, b):
pass
def bar(x, y):
pass
def baz(x,y,z):
pass我想要一个函数is_compatible(a,b),当传递foo和bar时返回True,传递bar和baz时返回False,这样我就可以在实际调用它们之前检查它们是否可互换。
发布于 2009-06-20 18:02:08
inspect.getargspec(func)
获取函数参数的名称和默认值。返回一个包含四个元素的元组:(args,varargs,varkw,default)。args是参数名称的列表(它可能包含嵌套列表)。varargs和varkw是*和**参数的名称或无。defaults是默认参数值的元组,如果没有默认参数,则为None;如果该元组有n个元素,则它们对应于args中列出的最后n个元素。
版本2.6中的更改:返回命名元组ArgSpec(args,varargs,keywords,defaults)。
发布于 2009-06-20 18:02:28
您将基于什么来实现兼容性?参数的数量?Python具有可变长度的参数列表,因此您永远不会知道两个函数在这种意义上是否兼容。数据类型?Python使用了鸭子类型,所以除非您在函数中使用isinstance测试或类似的测试,否则对兼容性测试所基于的数据类型没有约束。
所以简而言之:不。
你应该编写好的文档字符串,这样你的API的任何用户都知道他给你的函数必须做什么,然后你应该相信你得到的函数是正确的。任何“兼容性”检查要么会排除可能的有效函数,要么会给你一个错误的感觉,那就是“一切都像它应该的样子”。
公开API的典型方式是:编写好的文档,让人们知道他们需要知道什么,并相信他们做的是正确的事情。在关键位置,您仍然可以使用try: except:,但任何因为不关心阅读文档而滥用您的API的人都不应该被给予错误的安全感。如果有人读了你的文档,并希望以一种完全可接受的方式使用它,就不应该因为他们声明函数的方式而拒绝使用它的可能性。
发布于 2020-07-28 20:59:20
虽然Python是动态类型语言,但python中有一个很强的类型概念(强类型)。在引入类型提示之后,现在可以检查函数的互换性。但首先让我们陈述以下几点:
对 执行操作
如果类型t2是t1类型的子类型,那么t1类型的对象应该可以替换为t2类型的对象。
Callable 类型的对数/协方差类型:
协方差是协方差( Callable[[], float] )的一个子类型。
这一点很直观:最终计算结果为int的可调用函数可以替换计算结果为float的函数(暂时忽略args列表)。
逆方差是Callable[[int], None] (逆方差)的一个子类型。
这有点令人困惑,但请记住,对整数进行操作的callable可能会执行浮点数上没有定义的操作,例如,>> <<,而对float进行操作的callable肯定不会执行任何没有在整数上定义的操作(因为integer是float的子类型)。因此,在浮点型上操作的可调用对象可以替换在整数上操作的可调用对象,而不是通过反之亦然(忽略返回类型)。
从上面我们得出结论:对于可调用的c1可被可调用的c2替换,应满足以下条件:
c2返回类型应为c1返回类型的子类型。c1:(a1, a2,...an)的参数列表的c2:(b1, b2,...bn),a1的参数列表应为< a1 >D46、b2的a2子类型等。Implementation
简单的实现是(忽略kwargs和可变长度参数列表):
from inspect import getfullargspec
def issubtype(func1, func2):
"""Check whether func1 is a subtype of func2, i.e func1 could replce func2"""
spec1, spec2 = getfullargspec(func1), getfullargspec(func2)
if not issubclass(spec1.annotations['return'], spec2.annotations['return']):
return False
return all((issubclass(spec2.annotations[arg2], spec1.annotations[arg1]) for (arg1, arg2) in zip(spec1.args, spec2.args)))示例:
from numbers import Integral, Real
def c1(x :Integral) -> Real:
pass
def c2(x: Real) -> Integral:
pass
print(issubtype(c2, c1))
print(issubtype(c1, c2))
class Employee:
pass
class Manager(Employee):
pass
def emp_salary(emp :Employee) -> Integral:
pass
def man_salary(man :Manager) -> Integral:
pass
print(issubtype(emp_salary, man_salary))
print(issubtype(man_salary, emp_salary))输出:
True
False
True
Falsehttps://stackoverflow.com/questions/1022124
复制相似问题