首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >检查两个python函数(或方法)的兼容性

检查两个python函数(或方法)的兼容性
EN

Stack Overflow用户
提问于 2009-06-20 17:57:48
回答 3查看 413关注 0票数 3

有没有可能检查两个python函数是否可以互换?例如,如果我有

代码语言:javascript
复制
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,这样我就可以在实际调用它们之前检查它们是否可互换。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2009-06-20 18:02:08

看一看inspect.getargspec()

inspect.getargspec(func)

获取函数参数的名称和默认值。返回一个包含四个元素的元组:(args,varargs,varkw,default)。args是参数名称的列表(它可能包含嵌套列表)。varargs和varkw是*和**参数的名称或无。defaults是默认参数值的元组,如果没有默认参数,则为None;如果该元组有n个元素,则它们对应于args中列出的最后n个元素。

版本2.6中的更改:返回命名元组ArgSpec(args,varargs,keywords,defaults)。

票数 3
EN

Stack Overflow用户

发布于 2009-06-20 18:02:28

您将基于什么来实现兼容性?参数的数量?Python具有可变长度的参数列表,因此您永远不会知道两个函数在这种意义上是否兼容。数据类型?Python使用了鸭子类型,所以除非您在函数中使用isinstance测试或类似的测试,否则对兼容性测试所基于的数据类型没有约束。

所以简而言之:不。

你应该编写好的文档字符串,这样你的API的任何用户都知道他给你的函数必须做什么,然后你应该相信你得到的函数是正确的。任何“兼容性”检查要么会排除可能的有效函数,要么会给你一个错误的感觉,那就是“一切都像它应该的样子”。

公开API的典型方式是:编写好的文档,让人们知道他们需要知道什么,并相信他们做的是正确的事情。在关键位置,您仍然可以使用try: except:,但任何因为不关心阅读文档而滥用您的API的人都不应该被给予错误的安全感。如果有人读了你的文档,并希望以一种完全可接受的方式使用它,就不应该因为他们声明函数的方式而拒绝使用它的可能性。

票数 4
EN

Stack Overflow用户

发布于 2020-07-28 20:59:20

虽然Python是动态类型语言,但python中有一个很强的类型概念(强类型)。在引入类型提示之后,现在可以检查函数的互换性。但首先让我们陈述以下几点:

对 执行操作

如果类型t2t1类型的子类型,那么t1类型的对象应该可以替换为t2类型的对象。

Callable 类型的对数/协方差类型:

协方差是协方差( Callable[[], float] )的一个子类型。

这一点很直观:最终计算结果为int的可调用函数可以替换计算结果为float的函数(暂时忽略args列表)。

逆方差是Callable[[int], None] (逆方差)的一个子类型。

这有点令人困惑,但请记住,对整数进行操作的callable可能会执行浮点数上没有定义的操作,例如,>> <<,而对float进行操作的callable肯定不会执行任何没有在整数上定义的操作(因为integer是float的子类型)。因此,在浮点型上操作的可调用对象可以替换在整数上操作的可调用对象,而不是通过反之亦然(忽略返回类型)。

从上面我们得出结论:对于可调用的c1可被可调用的c2替换,应满足以下条件:

  1. c2返回类型应为c1返回类型的子类型。c1(a1, a2,...an)的参数列表的
  2. c2(b1, b2,...bn)a1的参数列表应为< a1 >D46、b2a2子类型等。

Implementation

简单的实现是(忽略kwargs和可变长度参数列表):

代码语言:javascript
复制
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)))

示例:

代码语言:javascript
复制
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))

输出:

代码语言:javascript
复制
True
False
True
False
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1022124

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档