Ich habe eine Funktion, die viele Parameter akzeptiert, und da ich mich nicht an ihre Positionen erinnern möchte, habe ich mich für benannte Argumente entschieden

def f(a=None, b=None, c=None):
    print a,b,c
f('test', c=5, b='second param')
>>> test second param 5

Normalerweise ändere ich jetzt immer nur einen Parameter, daher möchte ich die Funktion aufrufen, indem ich nur f (c = 3.14) eingebe, wobei das beabsichtigte Ergebnis f (a = a, b = b, c = 3.14) ist, nämlich jeder Argumente, die nicht explizit übergeben werden, sollten aus dem lokalen Bereich gelesen werden.

Aber natürlich funktioniert es nicht, da ich zur Verwendung benannter Argumente einen Standardwert festlegen muss. Wenn ich stattdessen ** kwargs verwende, werden die Argumente einfach ignoriert

def f(**kwargs):
    print a,b,c
a=1; b=2; c=3
f(a=2, b=4, c=8)
>>> 1 2 3 # instead of 2 4 8

Früher habe ich für jeden Parameter eine neue Funktion definiert, aber dieser Ansatz gefällt mir nicht, obwohl er bisher am effektivsten war

def fc(c_new):
    return f(a, b, c_new)

Wie kann ich die Funktion veranlassen, die Variablen in ihrem aktuellen Bereich als Standardwerte für die benannten Argumente zu verwenden?

5
DenDenDo 27 Nov. 2013 im 15:31

4 Antworten

Beste Antwort

Hier ist eine Lösung mit einem Dekorateur:

from functools import wraps
from inspect import getcallargs


def defaults_from_globals(f):
    @wraps(f)
    def new(**kwargs):
        # filter only those vars, that are in the list of function's named args
        from_globals = {arg: globals()[arg] for arg in getcallargs(f)}
        # overwrite them with user supplied kwargs
        from_globals.update(kwargs)
        return f(**from_gobals)

    return new


@defaults_from_globals
def f(a=None, b=None, c=None):
    return a, b, c


a = 1
b = 2
c = 3

print f(a=2, b=4) # 2 4 3
8
Alexander Zhukov 8 Juni 2018 im 10:13

Ich denke, Sie sollten Dekorateure verwenden

import functools

_last_args = {}
def foo(f):
    @functools.wraps(f)
    def wrapper( *args, **kwargs):
        _last_args.update(kwargs)
        ret =  f(*args, **_last_args)
        return ret
    return wrapper

@foo
def bar(a=None,b=None,c=None):
    print(a,b,c)

bar(a=1,b=2,c=3)
bar(a=10,b=20)
bar(a=100)

Druckt:

1 2 3
10 20 3
100 20 3
0
Foo Bar User 27 Nov. 2013 im 12:00

Um eine globale Variable in Python zu initialisieren, sollte es sich um ein globales Schlüsselwort handeln

Versuche dies:

def f(a=None, b=None, c=None):
    print a,b,c

global a=1
global b=2
global c=3
f(a=2, b=4, c=8)
>>>2,4,8
-2
psorab 27 Nov. 2013 im 11:53

Der Vollständigkeit halber ist hier eine weitere Lösung, die ich gerade gefunden habe. Es ist eher ein schmutziger Hack, da die Verwendung von exec in den meisten Fällen verpönt ist *, aber einfacher zu verstehen ist.

* ) In diesem Fall hat der Benutzer die Kontrolle über den Code und es liegt nicht in seinem Interesse, seine eigene Arbeit absichtlich zu vermasseln

def f(x=None, y=None, z=None):
    for  key,val in locals().items():
        if val==None: exec("%s = globals()[key]"%key)
    print x,y,z
1
BartoszKP 28 Nov. 2013 im 13:00