Was ist in Python 2.x (ich verwende 2.7) der richtige Weg, um Standardargumente mit *args
und zu verwenden **kwargs
?
Ich habe eine Frage zu SO im Zusammenhang mit diesem Thema gefunden, aber das ist für Python 3 :
Aufrufen einer Python-Funktion mit * args, ** kwargs und optionalen / Standardargumenten
Dort heißt es, diese Methode funktioniert:
def func(arg1, arg2, *args, opt_arg='def_val', **kwargs):
#...
In 2.7 ergibt sich a SyntaxError
. Gibt es eine empfohlene Möglichkeit, eine solche Funktion zu definieren?
Ich habe es so gemacht, aber ich würde vermuten, dass es eine schönere Lösung gibt.
def func(arg1, arg2, *args, **kwargs):
opt_arg ='def_val'
if kwargs.__contains__('opt_arg'):
opt_arg = kwargs['opt_arg']
#...
python
python-2.7
Codeforester
quelle
quelle
__contains__
. Verwenden Sie immerin
:'opt_arg' in kwargs
. (Noch besser:kwargs.get('opt_arg', 'def_val')
wie in mgilsons Antwort).Antworten:
Stellen Sie einfach die Standardargumente vor
*args
:def foo(a, b=3, *args, **kwargs):
Nun
b
wird explizit festgelegt , wenn Sie es als Schlüsselwort - Argument oder das zweite Positions Argument übergeben.Beispiele:
foo(x) # a=x, b=3, args=(), kwargs={} foo(x, y) # a=x, b=y, args=(), kwargs={} foo(x, b=y) # a=x, b=y, args=(), kwargs={} foo(x, y, z, k) # a=x, b=y, args=(z, k), kwargs={} foo(x, c=y, d=k) # a=x, b=3, args=(), kwargs={'c': y, 'd': k} foo(x, c=y, b=z, d=k) # a=x, b=z, args=(), kwargs={'c': y, 'd': k}
Beachten Sie, dass dies insbesondere
foo(x, y, b=z)
nicht funktioniert, dab
es in diesem Fall nach Position zugewiesen wird.Dieser Code funktioniert auch in Python 3. Wenn Sie in Python 3 das Standardargument nach setzen,
*args
wird es zu einem "Nur-Schlüsselwort" -Argument, das nur nach Name und nicht nach Position angegeben werden kann. Wenn Sie in Python 2 nur ein Schlüsselwortargument verwenden möchten, können Sie die Lösung von @ mgilson verwenden.quelle
*args
. Ihr Weg ist korrekt, wenn Sie ein Nur-Schlüsselwort-Argument möchten.*args
, nein. Aus diesem Grund wurde die Funktionalität zu Python 3 hinzugefügt. In der Regel werden Standardargumente in Python 2 als etwas Offensichtliches wie 0 angegeben,None
damit sie explizit übergeben werden können.Die Syntax in der anderen Frage lautet nur python3.x und gibt nur Argumente für Schlüsselwörter an. Unter python2.x funktioniert es nicht.
Für python2.x würde ich
pop
es aus kwargs heraus machen:def func(arg1, arg2, *args, **kwargs): opt_arg = kwargs.pop('opt_arg', 'def_val')
quelle
Sie können auch einen Dekorateur wie diesen verwenden:
import functools def default_kwargs(**defaultKwargs): def actual_decorator(fn): @functools.wraps(fn) def g(*args, **kwargs): defaultKwargs.update(kwargs) return fn(*args, **defaultKwargs) return g return actual_decorator
Dann machen Sie einfach:
@default_kwargs(defaultVar1 = defaultValue 1, ...) def foo(*args, **kwargs): # Anything in here
Zum Beispiel:
@default_kwargs(a=1) def f(*args, **kwargs): print(kwargs['a']+ 1) f() # Returns 2 f(3) # Returns 4
quelle
Wenn Sie sich an Ihren Lösungsansatz halten und versuchen, ihn allgemeiner und kompakter zu gestalten, würde ich Folgendes in Betracht ziehen:
>>> def func(arg1, arg2, *args, **kwargs): ... kwargs_with_defaults = dict({'opt_arg': 'def_val', 'opt_arg2': 'default2'}, **kwargs) ... #... ... return arg1, arg2, args, kwargs_with_defaults >>> func('a1', 'a2', 'a3', 'a5', x='foo', y='bar') ('a1', 'a2', ('a3', 'a5'), {'opt_arg2': 'default2', 'opt_arg': 'def_val', 'y': 'bar', 'x': 'foo'}) >>> func('a1', 'a2', 'a3', 'a5', opt_arg='explicit_value', x='foo', y='bar') ('a1', 'a2', ('a3', 'a5'), {'opt_arg2': 'default2', 'opt_arg': 'explicit_value', 'y': 'bar', 'x': 'foo'})
quelle
Eine andere Möglichkeit, mit Python 2.x umzugehen:
def foo(*args, **kwargs): if 'kwarg-name' not in kwargs.keys(): kwargs['kwarg-name'] = 'kwarg-name-default-value' return bar(*args, **kwargs)
Dies behandelt die Weitergabe beliebig
*args
an den zugrunde liegenden Anruf im Gegensatz zu @ nneonneos Antwort.quelle
'opt_arg'
anstelle von< kwarg-name >
und'def_val'
anstelle von< kwarg-name-default-value >
Diese Antwort ist eine Erweiterung dessen, was Daniel Américo vorgeschlagen hat .
Dieser Dekorateur weist Standard-Kwarg-Werte zu, wenn diese nicht genau definiert sind.
from functools import wraps def force_kwargs(**defaultKwargs): def decorator(f): @wraps(f) def g(*args, **kwargs): new_args = {} new_kwargs = defaultKwargs varnames = f.__code__.co_varnames new_kwargs.update(kwargs) for k, v in defaultKwargs.items(): if k in varnames: i = varnames.index(k) new_args[(i, k)] = new_kwargs.pop(k) # Insert new_args into the correct position of the args. full_args = list(args) for i, k in sorted(new_args.keys()): if i <= len(full_args): full_args.insert(i, new_args.pop((i, k))) else: break # re-insert the value as a key-value pair for (i, k), val in new_args.items(): new_kwargs[k] = val return f(*tuple(full_args), **new_kwargs) return g return decorator
Ergebnis
@force_kwargs(c=7) def f(a, b='B', c='C', d='D', *args, **kw): return a, b, c, d, args, kw # a b c d args kwargs f('r') # 'r', 'B', 7, 'D', (), {} f(1,2,3) # 1, 2, 7, 3, (), {} f(1, 2, 3, b=3, c=9, f='F') # 1, 3, 9, 2, (3,), {'f': 'F'}
Variante
Wenn Sie die in der Funktionsdefinition angegebenen Standardwerte verwenden möchten, können Sie mit auf das Argument Standardwerte zugreifen
f.func_defaults
, in dem die Standardwerte aufgelistet sind. Sie müsstenzip
sie mit dem Ende von versehenf.__code__.varnames
, um diese Standardwerte mit den Variablennamen abzugleichen.quelle