我想找出Python中方法的优点(它接收的参数数量)。 现在我正在这样做:
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
答案 0 :(得分:46)
模块inspect
是您的朋友 - 请参阅the online docs! inspect.getargspec(func)
会返回一个包含四个项目的元组,args, varargs, varkw, defaults
:len(args)
是“主要的arity”,但如果你有varargs
和/或arity,那么arity可以是从无到有的任何东西varkw
不是None
,如果defaults
不是None
,则可能会省略(并默认)某些参数。你怎么把它变成一个数字,打败了我,但大概你在这件事上有你的想法! - )
这适用于Python编码的函数,但不适用于C编码函数。 Python C API中没有任何内容允许C编码函数(包括内置函数)公开其内省签名,除非通过其docstring(或者可选地通过Python 3中的注释);所以,如果其他方法失败,将需要回退到docstring解析作为最后一个沟渠(当然,文档字符串可能也会丢失,在这种情况下,函数仍然是个谜)。
答案 1 :(得分:5)
使用装饰器来装饰方法,例如
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()
现在实施_arity
功能,根据您的需要计算arg数
答案 2 :(得分:2)
理想情况下,您希望将arity函数作为Python仿函数的方法进行修补。方法如下:
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()函数是正确的。可变函数怎么样?你甚至想要一个答案吗?
答案 3 :(得分:2)
这是我能够想到的唯一一种在确定函数(最小)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
如您所见,如果函数采用可变数量的参数,这将确定 minimum arity。它也不会考虑类或实例方法的self或cls参数。
但是说实话,我不会在生产环境中使用这个功能,除非我确切知道会调用哪些函数,因为有很多愚蠢的错误空间。这可能会破坏目的。
答案 4 :(得分:0)
这是使用元类的另一个尝试,因为我使用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()