2009-06-13 47 views
28

我想找出一個方法,在Python的元數(它接收的參數個數)的元數。 現在我這樣做:如何找出一個方法,在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 
+1

help()有什麼問題?這不是你所需要的嗎? – 2009-06-13 09:49:34

+7

我需要以編程方式使用它,所以我不想解析文本以返回一個數字。 – 2009-06-13 15:21:04

+2

你有什麼要求def a(* args)的元素:`? – 2009-06-13 20:41:56

回答

44

模塊inspect來自Python的標準庫是你的朋友 - 見the online docsinspect.getargspec(func)返回四個選項,args, varargs, varkw, defaults一個元組:len(args)是「主元數」,但如果你有varargs和/或varkwNone元數可以是任何東西到無窮大,而一些參數可以省略(和默認的),如果defaults不是None。你怎麼把它轉換成一個數字,我百思不得其解,但想必你有你的想法在這個問題上 - !)

這適用於Python的編碼功能,而不是C-編碼的。 Python C API中的任何內容都不允許C編碼函數(包括內置函數)公開自己的簽名以進行自省,除非通過文檔字符串(或者可選地通過Python 3中的註釋);所以,你會需要回落到文檔字符串解析爲最後一搏,如果其他方法失敗(當然,文檔字符串可能會丟失過多,在這種情況下功能將仍然是一個謎)。

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函數來計算根據您的需求

2

理想ARG計數,你會希望猴子修補元數的功能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()函數是正確的。可變參數函數呢?你甚至想要一個答案呢?

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() 
2

這是我認爲在確定函數(最小)元數時應該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參數。儘管如此,我不會在生產環境中使用這個函數,除非我確切地知道哪些函數會被調用,但是因爲有很多愚蠢的錯誤空間。這可能會破壞目的。

相關問題