it-swarm.com.de

Methodenparameternamen in Python abrufen

In Anbetracht der Python-Funktion:

def aMethod(arg1, arg2):
    pass

Wie kann ich die Anzahl und Namen der Argumente extrahieren? Wenn ich also einen Verweis auf die Funktion führe, möchte ich, dass die Funktion [etwas] zurückgegeben wird ("arg1", "arg2").

Das Verwendungsszenario dafür ist, dass ich einen Dekorateur habe, und ich möchte die Methodenargumente in derselben Reihenfolge verwenden, in der sie für die eigentliche Funktion als Schlüssel erscheinen. Wie würde der Dekorateur aussehen, wenn "a, b" gedruckt ist, wenn ich aMethod ("a", "b") rufe?

194
Staale

Schauen Sie sich das Modul inspect an - dies führt die Überprüfung der verschiedenen Codeobjekteigenschaften für Sie durch.

>>> inspect.getfullargspec(aMethod)
(['arg1', 'arg2'], None, None, None)

Die anderen Ergebnisse sind der Name der Variablen * args und ** kwargs sowie die angegebenen Standardwerte. dh.

>>> def foo(a,b,c=4, *arglist, **keywords): pass
>>> inspect.getfullargspec(foo)
(['a', 'b', 'c'], 'arglist', 'keywords', (4,))

Beachten Sie, dass einige Callables in bestimmten Python-Implementierungen möglicherweise nicht introspektiv sind. In CPython zum Beispiel bieten einige in C definierte integrierte Funktionen keine Metadaten zu ihren Argumenten. Als Ergebnis erhalten Sie ValueError, wenn Sie inspect.getfullargspec() mit einer integrierten Funktion verwenden.

Seit Python 3.3 können Sie auch die Datei inspect.signature () verwenden, um die Aufrufsignatur eines aufrufbaren Objekts zu kennen:

>>> inspect.signature(foo)
<Signature (a, b, c=4, *arglist, **keywords)>
308
Brian

In CPython beträgt die Anzahl der Argumente

aMethod.func_code.co_argcount

und ihre Namen stehen am Anfang von

aMethod.func_code.co_varnames

Dies sind Implementierungsdetails von CPython, daher funktionieren diese Funktionen wahrscheinlich nicht in anderen Implementierungen von Python, wie z. B. IronPython und Jython.

Eine tragbare Möglichkeit, Argumente für den Durchgang zuzulassen, ist die Definition Ihrer Funktion mit der Signatur func(*args, **kwargs). Dies wird häufig in z. matplotlib, wobei die äußere API-Schicht viele Schlüsselwortargumente an die untergeordnete API übergibt.

92

In einer Decorator-Methode können Sie Argumente der Originalmethode auf folgende Weise auflisten:

import inspect, itertools 

def my_decorator():

        def decorator(f):

            def wrapper(*args, **kwargs):

                # if you want arguments names as a list:
                args_name = inspect.getargspec(f)[0]
                print(args_name)

                # if you want names and values as a dictionary:
                args_dict = dict(itertools.izip(args_name, args))
                print(args_dict)

                # if you want values as a list:
                args_values = args_dict.values()
                print(args_values)

Wenn der **kwargs für Sie wichtig ist, wird es etwas kompliziert:

        def wrapper(*args, **kwargs):

            args_name = list(OrderedDict.fromkeys(inspect.getargspec(f)[0] + kwargs.keys()))
            args_dict = OrderedDict(list(itertools.izip(args_name, args)) + list(kwargs.iteritems()))
            args_values = args_dict.values()

Beispiel:

@my_decorator()
def my_function(x, y, z=3):
    pass


my_function(1, y=2, z=3, w=0)
# prints:
# ['x', 'y', 'z', 'w']
# {'y': 2, 'x': 1, 'z': 3, 'w': 0}
# [1, 2, 3, 0]
21
Mehdi Behrooz

Hier ist etwas, von dem ich denke, dass es mit einem Dekorateur funktioniert, was Sie wollen.

class LogWrappedFunction(object):
    def __init__(self, function):
        self.function = function

    def logAndCall(self, *arguments, **namedArguments):
        print "Calling %s with arguments %s and named arguments %s" %\
                      (self.function.func_name, arguments, namedArguments)
        self.function.__call__(*arguments, **namedArguments)

def logwrap(function):
    return LogWrappedFunction(function).logAndCall

@logwrap
def doSomething(spam, eggs, foo, bar):
    print "Doing something totally awesome with %s and %s." % (spam, eggs)


doSomething("beans","rice", foo="wiggity", bar="wack")

Führen Sie es aus, um folgende Ausgabe zu erhalten:

C:\scripts>python decoratorExample.py
Calling doSomething with arguments ('beans', 'rice') and named arguments {'foo':
 'wiggity', 'bar': 'wack'}
Doing something totally awesome with beans and rice.
13
hlzr

Ich denke, was Sie suchen, ist die Methode der Einheimischen - 


In [6]: def test(a, b):print locals()
   ...: 

In [7]: test(1,2)              
{'a': 1, 'b': 2}
11
Damian

Python 3.5+:

DeprecationWarning: inspect.getargspec () ist veraltet, verwenden Sie stattdessen inspect.signature ()

Also vorher:

func_args = inspect.getargspec(function).args

Jetzt:

func_args = list(inspect.signature(function).parameters.keys())

Zu testen:

'arg' in list(inspect.signature(function).parameters.keys())

Da wir die Funktion 'function' haben, die das Argument 'arg' verwendet, wird dies als "True" ausgewertet, ansonsten als "False".

Beispiel aus der Python-Konsole:

Python 3.6.0 (v3.6.0:41df79263a11, Dec 23 2016, 07:18:10) [MSC v.1900 32 bit (Intel)] on win32
>>> import inspect
>>> 'iterable' in list(inspect.signature(sum).parameters.keys())
True
5
Peter Majko

Die Python 3-Version ist:

def _get_args_dict(fn, args, kwargs):
    args_names = fn.__code__.co_varnames[:fn.__code__.co_argcount]
    return {**dict(Zip(args_names, args)), **kwargs}

Die Methode gibt ein Wörterbuch zurück, das sowohl args als auch kwargs enthält.

4
argaen

Gibt eine Liste mit Argumentnamen zurück, kümmert sich um Teilfunktionen und reguläre Funktionen:

def get_func_args(f):
    if hasattr(f, 'args'):
        return f.args
    else:
        return list(inspect.signature(f).parameters)
2
lovesh

In Python 3. + mit dem Signature-Objekt ist eine einfache Möglichkeit, eine Zuordnung zwischen Argumentnamen zu Werten zu erhalten, die bind()-Methode der Signatur!

Hier ist zum Beispiel ein Dekorator zum Drucken einer Karte wie folgt:

import inspect

def decorator(f):
    def wrapper(*args, **kwargs):
        bound_args = inspect.signature(f).bind(*args, **kwargs)
        bound_args.apply_defaults()
        print(dict(bound_args.arguments))

        return f(*args, **kwargs)

    return wrapper

@decorator
def foo(x, y, param_with_default="bars", **kwargs):
    pass

foo(1, 2, extra="baz")
# This will print: {'kwargs': {'extra': 'baz'}, 'param_with_default': 'bars', 'y': 2, 'x': 1}
2
Kfir Eisner

Update für Brians Antwort :

Wenn eine Funktion in Python 3 über ausschließliche Schlüsselwörter verfügt, müssen Sie inspect.getfullargspec verwenden:

def yay(a, b=10, *, c=20, d=30):
    pass
inspect.getfullargspec(yay)

ergibt dies:

FullArgSpec(args=['a', 'b'], varargs=None, varkw=None, defaults=(10,), kwonlyargs=['c', 'd'], kwonlydefaults={'c': 20, 'd': 30}, annotations={})
2
user1981531

Um ein wenig zu aktualisieren Brians Antwort , gibt es jetzt einen netten Backport von inspect.signature, den Sie in älteren Python-Versionen verwenden können: funcsigs . Also würde meine persönliche Präferenz gehen

try:  # python 3.3+
    from inspect import signature
except ImportError:
    from funcsigs import signature

def aMethod(arg1, arg2):
    pass

sig = signature(aMethod)
print(sig)

Wenn Sie zum Spaß mit Signature Objekten spielen und sogar Funktionen mit zufälligen Signaturen dynamisch erstellen möchten, können Sie sich mein makefun Projekt ansehen.

0
smarie

Hier ist eine andere Möglichkeit, die Funktionsparameter ohne Verwendung eines Moduls abzurufen.

def get_parameters(func):
    keys = func.__code__.co_varnames[:func.__code__.co_argcount][::-1]
    sorter = {j: i for i, j in enumerate(keys[::-1])} 
    values = func.__defaults__[::-1]
    kwargs = {i: j for i, j in Zip(keys, values)}
    sorted_args = Tuple(
        sorted([i for i in keys if i not in kwargs], key=sorter.get)
    )
    sorted_kwargs = {}
    for i in sorted(kwargs.keys(), key=sorter.get):
        sorted_kwargs[i] = kwargs[i]      
    return sorted_args, sorted_kwargs


def f(a, b, c="hello", d="world"): var = a


print(get_parameters(f))

Ausgabe:

(('a', 'b'), {'c': 'hello', 'd': 'world'})
0
dildeolupbiten

In Python 3 müssen Sie *args und **kwargs in ein dict umwandeln (verwenden Sie OrderedDict für Python <3.6, um dict-Aufträge zu verwalten):

from functools import wraps

def display_param(func):
    @wraps(func)
    def wrapper(*args, **kwargs):

        param = inspect.signature(func).parameters
        all_param = {
            k: args[n] if n < len(args) else v.default
            for n, (k, v) in enumerate(param.items()) if k != 'kwargs'
        }
        all_param .update(kwargs)
        print(all_param)

        return func(**all_param)
    return wrapper
0
Alpha

inspect.signature ist sehr langsam. Der schnellste Weg ist

def f(a, b=1, *args, c, d=1, **kwargs):
   pass

f_code = f.__code__
f_code.co_varnames[:f_code.co_argcount + f_code.co_kwonlyargcount]  # ('a', 'b', 'c', 'd')
0