2010-01-18 10 views
13

Wenn ich eine Python-Funktion wie so haben:Get kwargs Innen Funktion

def some_func(arg1, arg2, arg3=1, arg4=2): 

Gibt es eine Möglichkeit, um zu bestimmen, welche Argumente nach Stichwort aus dem Inneren der Funktion übergeben wurden?

EDIT

Für diejenigen fragen, warum ich das brauche, ich keinen wirklichen Grund haben, kam es in einem Gespräch und Neugier erwischte den besseren von mir.

+1

Ich glaube nicht ... warum sollte man sich dann mit ** kw kümmern? – jldupont

+0

Es tut mir leid, aber wenn es nur deine Neugierde ist, die ich schließe, gibt es kein wirkliches Problem, keinen Anwendungsfall und niemand wird jemals ein Problem haben, von dem du träumst. – SilentGhost

+0

Eigentlich bin ich einmal auf dieses Problem gestoßen. Ich schrieb eine Funktion, um einen XML-Wrapper zu generieren (ein Start-Tag voranzustellen und ein End-Tag anzufügen) um einige CDATA und wollte, dass es wie 'def wrap (tag, contents = None, ** attrs) aussieht:', aber dann lief kopfüber in das Problem, dass Attribute Zeichen haben können, die Python-Bezeichner nicht haben können. Aber es war eine interessante Übung für ein paar Minuten. –

Antwort

14

Nein, es gibt keine Möglichkeit, es in Python-Code mit dieser Signatur zu tun - wenn Sie diese Informationen benötigen, müssen Sie die Signatur der Funktion ändern. Wenn Sie sich die Python-C-API ansehen, werden Sie sehen, dass die Argumente, die an eine normale Python-Funktion übergeben werden, immer ein Tupel plus ein Diktat sind, dh die Art, wie eine Signatur direkt widergespiegelt wird von *args, **kwargs. Das Tupel und das Diktat werden dann in bestimmte Positionsargumente und solche, die in der Signatur benannt sind, analysiert, obwohl sie mit dem Namen übergeben wurden, und die *a und **kw, falls vorhanden, nehmen nur den "Überlauf" von diesem Parsing - Nur zu diesem Zeitpunkt erhält Ihr Python-Code die Kontrolle und bis dahin sind die Informationen, die Sie anfordern (wie wurden die verschiedenen Argumente übergeben) nicht mehr in der Nähe.

Um die angeforderten Informationen zu erhalten, ändern Sie daher die Signatur in *a, **kw und machen Sie Ihre eigene Analyse/Validierung - dies wird "vom Ei zum Omelett", dh eine gewisse Menge an Arbeit, aber sicherlich machbar, während was du suchst, wäre "vom Omelett zurück zum Ei" ... einfach nicht machbar ;-).

+0

+1: interessante Analogie! – jldupont

+0

Nicht wirklich, es machte mich hungrig :( – gorsky

1

möchten Sie wissen, ob arg31 war, weil es von außerhalb weitergegeben wurde oder weil es ein Standardwert war? Nein, es gibt keinen Weg dies zu tun, soweit ich weiß. Der Hauptgrund, ich vermute, dass solche Kenntnisse nicht notwendig sind. Was normalerweise geschieht, ist die folgende:

>>> def func(a, b=None): 
    if b is None: 
# here we know that function was called as: 
# func('spam') or func('spam', None) or func('spam', b=None) or func(a='spam', b=None) 

     b = 42 
1

Just do it wie folgt aus:

def some_func (arg1, arg2, arg3=None, arg4=None): 
    if arg3 is None: 
     arg3 = 1 # default value 
    if arg4 is None: 
     arg4 = 2 # default value 

    # do something 

Auf diese Weise können Sie sehen, wenn etwas gesetzt wurde, und Sie auch in der Lage sind mit komplexeren Standardstrukturen zu arbeiten (wie Listen) ohne Probleme läuft wie diese:

>>> def test(arg=[]): 
     arg.append(1) 
     print(arg) 
>>> test() 
[1] 
>>> test() 
[1, 1] 
+0

Aber man kann immer noch nicht den Unterschied zwischen 'some_func sagen (1, 2, None, 4)' und 'some_func (1, 2, arg4 = 4)', zum Beispiel. –

+1

Warum brauchen Sie das? Named Argumente sind so, dass Sie andere optionale Parameter verlassen können (so müssen Sie nicht alle von ihnen schreiben). – poke

+0

Nun, das ist die Frage, nicht wahr? Mark ist das einzige Person, die das beantworten kann –

2

Sie sind so ziemlich gehen, um Ihre Funktion zu haben, neu zu definieren:

def some_func(*args, **kwargs): 

und machen Sie das Marshalling selbst. Es gibt keine Möglichkeit, den Unterschied zwischen Pass-by-Position, Pass-by-Keyword und Standard zu unterscheiden.

9

Hier ist meine Lösung über Dekorateure:

def showargs(function): 
    def inner(*args, **kwargs): 
     return function((args, kwargs), *args, **kwargs) 
    return inner 

@showargs 
def some_func(info, arg1, arg2, arg3=1, arg4=2): 
    print arg1,arg2,arg3,arg4 
    return info 

In [226]: some_func(1,2,3, arg4=4) 
1 2 3 4 
Out[226]: ((1, 2, 3), {'arg4': 4}) 

Es kann ein Weg sein, diese weiter zu bereinigen, aber dies scheint mir minimal aufdringlich und erfordert keine Änderung an den anrufenden Code.

Edit: Um tatsächlich zu testen, ob bestimmte Argumente nach Stichwort geben wurden, dann etwas tun, wie der folgende innerhalb von some_func:

args, kwargs = info 
if 'arg4' in kwargs: 
    print "arg4 passed as keyword argument" 

Haftungsausschluss: sollten Sie vielleicht überlegen, ob Sie wirklich interessieren wie die Argumente bestanden wurden. Dieser ganze Ansatz kann unnötig sein.

+0

auch Einheimische() denke ich –