如何在Python中找到方法的算术性

如何在Python中找到方法的算术性,python,metaprogramming,Python,Metaprogramming,我想了解Python中方法的arity(它接收的参数数量)。 现在我正在这样做: def arity(obj, method): return getattr(obj.__class__, method).func_code.co_argcount - 1 # remove self class Foo: def bar(self, bla): pass arity(Foo(), "bar") # => 1 我希望能够做到这一点: Foo().bar.arity(

我想了解Python中方法的arity(它接收的参数数量)。 现在我正在这样做:

def arity(obj, method):
  return getattr(obj.__class__, method).func_code.co_argcount - 1 # remove self

class Foo:
  def bar(self, bla):
    pass

arity(Foo(), "bar")   # => 1
我希望能够做到这一点:

Foo().bar.arity()   # => 1
更新:目前,上述功能因内置类型而失败,请提供相关帮助:

 # Traceback (most recent call last):
 #   File "bla.py", line 10, in <module>
 #     print arity('foo', 'split')  # =>
 #   File "bla.py", line 3, in arity
 #     return getattr(obj.__class__, method).func_code.co_argcount - 1 # remove self
 # AttributeError: 'method_descriptor' object has no attribute 'func_co
#回溯(最近一次呼叫最后一次):
#文件“bla.py”,第10行,在
#打印算术('foo','split')#=>
#文件“bla.py”,第3行,在arity中
#返回getattr(对象类方法)。func_code.co_argcount-1#删除self
#AttributeError:“方法描述符”对象没有属性“func\u co”

Python标准库中的模块
inspect
是您的朋友--请参阅
inspect.getargspec(func)
返回一个包含四个项的元组,
args,varargs,varkw,defaults
len(args)
是“主arity”,但是如果您有
varargs
和/或
varkw
而不是
None
,则arity可以是从该值到无穷大的任何值,并且可以省略(和默认)一些参数如果
默认值
不是
。你怎么把它变成一个单一的数字,我不知道,但你大概在这件事上有你的想法


这适用于Python编码的函数,但不适用于C编码的函数。Python C API中的任何内容都不允许C编码函数(包括内置函数)公开其签名以供内省,除非通过它们的docstring(或者可选地通过Python 3中的注释);因此,如果其他方法失败,您将需要退回到docstring解析作为最后一搏(当然,docstring也可能丢失,在这种情况下,函数将仍然是一个谜)。

使用装饰器装饰方法,例如

def arity(method):

  def _arity():
    return method.func_code.co_argcount - 1 # remove self

  method.arity = _arity

  return method

class Foo:
  @arity
  def bar(self, bla):
    pass

print Foo().bar.arity()

现在实现
\u arity
函数以根据需要计算arg计数

理想情况下,您希望将arity函数作为Python functor上的一种方法进行修补。以下是方法:

def arity(self, method):
    return getattr(self.__class__, method).func_code.co_argcount - 1

functor = arity.__class__
functor.arity = arity
arity.__class__.arity = arity
但是,CPython在C中实现了函子,您实际上无法修改它们。不过,这在PyPy中可能有效


假设arity()函数是正确的,就可以了。变量函数呢?你想知道答案吗?

这里是另一个使用元类的尝试,因为我使用的是python 2.5,但是使用2.6你可以很容易地修饰类

元类也可以在模块级别定义,因此它适用于所有类

from types import FunctionType

def arity(unboundmethod):
    def _arity():
        return unboundmethod.func_code.co_argcount - 1 # remove self
    unboundmethod.arity = _arity

    return unboundmethod

class AirtyMetaclass(type):
    def __new__(meta, name, bases, attrs):
        newAttrs = {}
        for attributeName, attribute in attrs.items():
            if type(attribute) == FunctionType:
                attribute = arity(attribute)

            newAttrs[attributeName] = attribute

        klass = type.__new__(meta, name, bases, newAttrs)

        return klass

class Foo:
    __metaclass__ = AirtyMetaclass
    def bar(self, bla):
        pass

print Foo().bar.arity()

这是我能想到的唯一一种方法,在确定函数的(最小)算术性时应该100%有效(至少在函数是用户定义的还是用C编写的方面)。但是,您应该确保此函数不会产生任何副作用,并且不会引发TypeError:

from functools import partial

def arity(func):
    pfunc = func
    i = 0
    while True:
        try:
            pfunc()
        except TypeError:
            pfunc = partial(pfunc, '')
            i += 1
        else:
            return i

def foo(x, y, z):
    pass

def varfoo(*args):
    pass

class klass(object):
    def klassfoo(self):
        pass

print arity(foo)
print arity(varfoo)

x = klass()
print arity(x.klassfoo)

# output
# 3
# 0
# 0
如您所见,这将确定函数接受可变数量参数时的最小算术数。它也不会考虑类或实例方法的self或cls参数


不过,老实说,我不会在生产环境中使用此函数,除非我确切知道将调用哪些函数,因为存在大量愚蠢错误的空间。这可能无法达到目的。

实际上,您可以使用元类来修饰类的所有方法,而不是手动完成。help()有什么问题吗?这不能满足您的需要吗?我需要以编程方式使用它,因此我不想解析文本以返回数字。您如何声明
def a(*args)的算术性:
?这适用于我定义的方法,但不适用于内置方法,请参阅inspect.getargspec(str.split)@Federico,您是对的:Python C API中没有任何内容允许C编码函数(内置函数)公开其签名以供内省,除了通过其docstring(或者可选地通过Python 3中的注释)之外;因此,不管你是否“喜欢”,如果其他方法失败,你都需要退回到docstring解析上来,作为最后的选择(当然docstring可能也会丢失);len(签名(a_func).parameters)