Erste Methode Parameternamen in Python
-
03-07-2019 - |
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")?
gedrucktLö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.