Frage

, um die Python-Funktion Gegeben:

def aMethod(arg1, arg2):
    pass

Wie kann ich die Anzahl und die Namen der Argumente extrahiert. Das heißt, da ich einen Verweis auf Func habe ich die func will. [Etwas] zurückzukehren ( "arg1", "arg2").

Das Nutzungsszenario dafür ist, dass ich einen Dekorateur, und ich mag die Methode Argumente in der gleichen Reihenfolge verwenden, dass sie für die eigentliche Funktion als Schlüssel erscheinen. Das heißt, wie würde der Dekorateur Blick, "a, b", wenn ich rufe aMethod ( "a", "b")?

gedruckt
War es hilfreich?

Lösung

Werfen Sie einen Blick auf die Modul prüfen - dies wird tun, um die Kontrolle der verschiedenen Code Objekteigenschaften für Sie.

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

Die anderen Ergebnisse sind der Name des * args und ** kwargs Variablen und die zur Verfügung gestellten 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 nicht in bestimmten Implementierungen von Python introspectable sein kann. Zum Beispiel in CPython einige eingebaute Funktionen definiert in C stellen keine Metadaten über ihre Argumente. Als Ergebnis werden Sie ValueError im Fall erhalten Sie inspect.getfullargspec() mit einer eingebauten Funktion verwenden.

Seit Python 3.3, können Sie auch die inspect.signature () um den Anruf Signatur eines abrufbaren Objekt zu wissen:

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

Andere Tipps

In CPython, die Anzahl der Argumente ist

aMethod.func_code.co_argcount

und ihre Namen sind am Anfang der

aMethod.func_code.co_varnames

Dies sind Details der Implementierung CPython, so dass dies wahrscheinlich auch in anderen Implementierungen von Python, wie Ironpython und Jython nicht funktioniert.

Eine tragbare Art und Weise „Pass-Through“ Argumente zuzulassen ist Ihre Funktion mit der Signatur func(*args, **kwargs) zu definieren. Dies wird eine Menge in zum Beispiel verwendet matplotlib, wobei die äußere Schicht API leitet viele Schlüsselwort Argumente an die untergeordneten API.

In einer Dekorateur Methode können Sie Argumente der ursprünglichen Methode auf diese Weise Liste:

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 die **kwargs für Sie wichtig sind, dann wird es ein bisschen kompliziert sein:

        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]

Hier ist etwas, das ich arbeiten denken, was Sie wollen, einen Dekorateur verwendet wird.

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, wird es die folgende Ausgabe ergeben:

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.

Ich denke, was Sie suchen ist die Einheimische Methode -


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

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

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 einen Wörterbuch beide args und kwargs enthält.

Python 3.5 +:

  

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

So zuvor:

func_args = inspect.getargspec(function).args

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

Zum Test:

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

Da wir Funktion ‚Funktion‘ haben, das Argument ‚arg‘ nimmt, wird dies bewerten, wie wahr, sonst als Falsch.

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

In Python 3 + mit dem Signature Objekt in der Hand, auf einfache Weise eine Zuordnung zwischen Argumentnamen auf Werte zu erhalten, wird mit der bind() Methode Unterschrift!

Zum Beispiel, hier ist ein Dekorateur zum Drucken einer Karte wie folgt aus:

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}

Gibt eine Liste von Argumentnamen, kümmert sich um partials und regelmäßige Funktionen:

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

Update für Brians Antwort :

Wenn eine Funktion in Python 3 hat keyword-nur Argumente, dann 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={})

In Python 3 unten ist zu *args und **kwargs in eine dict (Verwendung OrderedDict für Python <3,6 dict Aufträge zu erhalten) zu machen:

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

Um ein wenig Brian zu aktualisieren Antwort , gibt es jetzt eine schöne Rückportierung von inspect.signature, die Sie in älteren Python verwenden können Versionen: funcsigs . Also meine persönliche Präferenz würde für

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

def aMethod(arg1, arg2):
    pass

sig = signature(aMethod)
print(sig)

Für Spaß, wenn Sie in dem Spiel mit Signature Objekten interessiert sind und auch Funktionen mit Zufallssignaturen Erstellung dynamisch können Sie einen Blick auf meinem makefun Projekt.

Was ist dir() und vars() jetzt?

Es scheint, tun genau das, was gefragt wird Super einfach ...

muss innerhalb der Funktion Umfang aufgerufen werden.

Aber vorsichtig sein, dass sie zurückkehren alle lokale Variablen so sicher sein, sie gleich am Anfang der Funktion zu tun, wenn nötig.

Beachten Sie auch, dass, wie in den Kommentaren darauf hingewiesen, das es nicht von außerhalb des Rahmens durchgeführt werden läßt. Also nicht genau OPs Szenario aber immer noch stimmt mit der Frage Titel. Daher meine Antwort.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top