2009-06-13 6 views
28

Ich möchte herausfinden, die Funktionalität einer Methode in Python (die Anzahl der Parameter, die es empfängt). Gerade jetzt das ich tue:Wie finde ich die Richtigkeit einer Methode in 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 

Ich möchte in der Lage sein, dies zu erreichen:

Foo().bar.arity() # => 1 

aktualisieren: Im Augenblick ist die obige Funktion nicht mit eingebauten Typen, jede Hilfe zu diesem Thema auch anerkannt werden würde:

Standardbibliothek
# 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

Was ist falsch mit Hilfe()? Was macht das nicht, was Sie brauchen? –

+7

Ich muss es programmatisch verwenden, also habe ich keine Lust, den Text zu analysieren, um eine Zahl zurückzugeben. –

+2

Was beanspruchen Sie die Aritness von 'def a (* args):'? –

Antwort

44

Modul inspect von Python ist dein Freund - siehe the online docs! inspect.getargspec(func) gibt ein Tupel mit vier Elementen, args, varargs, varkw, defaults: len(args) ist die „primäre arity“, aber arity aus, dass bis ins Unendliche alles sein, wenn Sie varargs und/oder varkw nicht None und einige Argumente weggelassen werden können (und in Verzug geratene), wenn defaults ist nicht None. Wie du das in eine einzige Zahl umwandelst, schlägt mich, aber vermutlich hast du deine Ideen in der Sache! -)

Das gilt für Python-kodierte Funktionen, aber nicht für C-kodierte. Nichts in der Python-C-API ermöglicht C-codierten Funktionen (einschließlich Einbauten), ihre Signatur für Introspektion freizugeben, außer über ihren Docstring (oder optional über Annotationen in Python 3); Also, Sie werden müssen auf Docstring Parsing als letzten Graben fallen, wenn andere Ansätze fehlschlagen (natürlich könnte die Docstring auch fehlen, in diesem Fall wird die Funktion ein Geheimnis bleiben).

+0

Das funktioniert für meine Methoden, die ich definiere, aber nicht für eingebaute, siehe inspect.getargspec (str.split) –

+0

@Federico, du bist richtig: nichts in der Python C-API lässt C-codierte Funktionen (welche eingebaut sind)) ihre Signatur für Introspektion freizugeben, außer über ihren Docstring (oder optional über __annotations__ in Python 3); Also, "fühlen Sie sich wie es" oder nicht, Sie müssen auf Docstring Parsing als letzten Graben zurückgreifen, wenn andere Ansätze fehlschlagen (natürlich könnte der Docstring auch fehlen). –

+0

meine Antwort bearbeiten, um diese Klarstellung hinzuzufügen. –

5

Verwenden Sie einen Decorator, um Methoden z.

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

implementieren Jetzt _arity Funktion arg zählen auf Ihre Bedürfnisse

+0

Tatsächlich kann man mit Metaklasse alle Methoden einer Klasse dekorieren, anstatt sie manuell zu machen –

2

Im Idealfall zu berechnen, würden Sie wollen, um die arity Funktion als Methode auf Python functors Affen-Patch. Und so geht's:

Aber CPython implementiert Funktoren in C, Sie können sie nicht wirklich ändern. Dies funktioniert möglicherweise in PyPy.

Das ist alles unter der Annahme, dass Ihre arity() - Funktion korrekt ist. Was ist mit variadischen Funktionen? Willst du überhaupt eine Antwort?

0

hier ist ein weiterer Versuch metaclass verwenden, wie ich Python 2.5 verwenden, aber mit 2,6 man konnte die Klasse

metaclass kann auch auf Modulebene definiert werden, so dass es funktioniert für alle Klassen

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

Nur so kann ich mir vorstellen, dass diese mindestens 100% effektiv sein sollte (zumindest im Hinblick darauf, ob die Funktion benutzerdefiniert oder in C geschrieben ist), um die (Mindest-) Funktion einer Funktion zu bestimmen.Allerdings sollten Sie sicher sein, dass diese Funktion keine Nebenwirkungen verursachen und dass es keine Typeerror werfen:

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 

Wie Sie sehen können, wird dies bestimmt die Minimum arity, wenn eine Funktion benötigt eine variable Anzahl von Argumenten. Außerdem wird das self- oder cls-Argument einer Klassen- oder Instanzmethode nicht berücksichtigt.

Um ganz ehrlich zu sein, würde ich diese Funktion nicht in einer Produktionsumgebung verwenden, es sei denn, ich wüsste genau, welche Funktionen aufgerufen werden, da es viel Platz für dumme Fehler gibt. Dies könnte den Zweck besiegen.

Verwandte Themen