如何在Python中找到方法的算术性
我想了解Python中方法的arity(它接收的参数数量)。 现在我正在这样做:如何在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(
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)