2012-06-25 4 views
8

ich eine Funktion mit zwei optionalen Parametern:Pythonic Lösung für die bedingten Argumente zu übergeben

def func(a=0, b=10): 
    return a+b 

Irgendwo anders in meinem Code ich etwas bedingtes Argument tue wie vorbei:

if a and b: 
    return func(a, b) 
elif a: 
    return func(a) 
elif b: 
    return func(b=b) 
else: 
    return func() 

Gibt es trotzdem zu Code in diesem Muster vereinfachen?

EDIT:

Nehmen wir an, dass ich nicht erlaubt Standard-Parameter Logik innerhalb func zu implementieren.

kann ich mehrere Funktionen haben wie func: func1, func2 und func3 würden alle enthalten die

a = a or 0 
b = b or 10 

Aussagen.

Aber ich rufe diese Reihe von Funktionen auf, um Doppelarbeit zu vermeiden. (Verwendung eines Dekorators)

+0

wenn "b == 0" absichtlich könnte dies einen Fehler verursachen. – moooeeeep

+0

Verschieben Sie das Muster in der Funktion? – Apalala

Antwort

12

Wenn Sie wollen in func nichts ändern dann die sinnvolle Option, um die Funktion ein dict von Argumenten zu übergeben würde:

>>> def func(a=0,b=10): 
... return a+b 
... 
>>> args = {'a':15,'b':15} 
>>> func(**args) 
30 
>>> args={'a':15} 
>>> func(**args) 
25 
>>> args={'b':6} 
>>> func(**args) 
6 
>>> args = {} 
>>> func(**args) 
10 

oder :

>>>func(**{'a':7}) 
17 
+0

Wie oft mit Python-Fragen ist die beste Antwort die einzig vernünftige Antwort! – jwg

+0

Dies ist die korrekte und mehr pythische Art, es zu tun – Anoyz

1

Warum diese Logik nicht an die Funktion übergeben?

def func(a, b): 
    a = a or 0 
    b = b or 10 
    return a + b 
+0

und wahrscheinlich Standardwerte machen 'None's oder so etwas – unkulunkulu

+2

@unkulunkulu: Ich glaube nicht. Die (originale) Funktion scheint nicht mit Variablenargumentlisten aufgerufen zu werden, sonst hätten wir 'def func (a = 0, b = 10) einfach machen können' und damit fertig werden. Satoru.Logic übergibt immer zwei Werte an die Funktion, aber sie können 'None' sein. –

+0

@moooeeeep: Nein - seine ursprüngliche Logik behandelt "0" und "None" genau so. –

1

Ihre Frage zu lösen, ich tun würde:

args = {'a' : a, 'b' : b} 
for varName, varVal in args.items(): 
    if not varVal: 
     del args[varName] 
f(**args) 

Aber der pythonic Weg wäre None als Standardwert in Ihrer Funktion zu verwenden:

f(a=None, b=None): 
    a = 10 if a is None else a 
    ... 

und einfach Rufen Sie f(a, b)

1

Geht durch die jetzt gelöschten Kommentare auf die Frage, dass der Scheck gemeint ist werden für die Variablen None anstatt Falsey sein, func so ändern, dass sie die Argumente Griffe None sein:

def func(a=None, b=None): 
    if a is None: 
     a = 0 
    if b is None: 
     b = 10 

Und dann rufen Sie einfach func(a, b) jedes Mal.

1

Standardmäßig nehmen alle Methoden in Python variable arguments.

Wenn Sie ein Argument in der Signatur der Methode definieren, machen Sie es explizit erforderlich. In Ihrem Snippet geben Sie einen Standardwert ein, der nicht optional ist.

Beachten Sie Folgendes:

>>> def func(a,b): 
... a = a if a else 0 
... b = b if b else 10 
... return a+b 
... 
>>> a = b = None 
>>> func(a,b) 
10 
>>> a = 5 
>>> b = 2 
>>> func(a,b) 
7 
>>> func() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: func() takes exactly 2 arguments (0 given) 

In diesem Code-Schnipsel, die beide a und b sind erforderlich, da ich keine Standardwerte definiert haben. Sie sind nicht optional.

Aber in Ihrem Ausschnitt, weil Sie ihnen Standards in der Methodensignatur gegeben haben sie aussehen wie sie sind optional, aber in der Tat haben sie nur Standardwerte ihnen zugewiesen.

>>> def func(a=0,b=10): 
... return a+b 
... 
>>> func() 
10 

Sie dies, indem Sie das Argument Liste im Inneren des Körpers des Verfahrens bestätigen kann:

>>> def func(a=b,b=10): 
... print locals().keys() 
... 
>>> func() 
['a', 'b'] 

Eine Möglichkeit, Ihre Funktion haben akzeptieren jede Anzahl von Argumenten (in anderen Worten, sie machen alle optional):

>>> def func(*args,**kwargs): 
... print len(args),args 
... print len(kwargs),kwargs 
... 
>>> func("hello","world",a=5,b=10) 
2 ('hello', 'world') 
2 {'a': 5, 'b': 10} 
>>> func() 
0() 
0 {} 
>>> func(1,2) 
2 (1, 2) 
0 {} 
>>> func(a) 
1 (5,) 
0 {} 
>>> func(foo="hello") 
0() 
1 {'foo': 'hello'} 
+0

warum nicht ersetzen 'a wenn eine else 0' mit' a oder 0', gleich mit '10'? – unkulunkulu

+0

@unkulunkulu: Du könntest für und gegen seine und meine Versionen argumentieren. Er ist expliziter, aber ausführlicher, meins ist kürzer und (vielleicht) einfacher, erfordert aber Kenntnisse über "Kurzschlüsse". –

+0

@TimPietzcker, ich dachte, dieses Wissen liefe im Blut eines Python-Programmierers, vielleicht irre ich mich, weil ich in der Sprache ziemlich neu bin. – unkulunkulu

1

Sie einen Dekorateur hinzufügen, die None Argumente beseitigen würde:

def skip_nones(fun): 
    def _(*args, **kwargs): 
     for a, v in zip(fun.__code__.co_varnames, args): 
      if v is not None: 
       kwargs[a] = v 
     return fun(**kwargs) 
    return _ 

@skip_nones 
def func(a=10, b=20): 
    print a, b 

func(None, None) # 10 20 
func(11, None) # 11 20 
func(None, 33) # 10 33 
+2

Funktioniert nicht - haben Sie es sogar versucht? 'func (None, 33)' druckt '33 20'. – WolframH

+0

@WolframH: Ich habe die Antwort bearbeitet. Danke für deine konstruktive und höfliche Kritik. – georg

+0

Gern geschehen. – WolframH

0

Ihre wörtliche Frage zu beantworten:

func(a or 0, b or 10) 

Edit: Kommentar Sehen Sie, warum sich die Frage nicht beantworten.

+0

Diese Lösung wurde zuvor vorgeschlagen und zurückgezogen, da sie die Standardwerte auf Seiten des Anrufers dupliziert. –

+0

@TimPietzcker OK. Ich habe wahrscheinlich falsch verstanden, welche Einschränkungen für welche Werte wo hingehören. Ich werde die Antwort hier lassen, damit andere nicht den gleichen Fehler machen. – WolframH

0

Dies könnte funktionieren:

def f(**kwargs): 
    a = get(kwargs, 0) 
    b = get(kwargs, 10) 
    return a + b 
+0

Okay - vielleicht nicht passend, da ich gerade mit Updates überschwemmt wurde ... –

+0

Was lässt Sie glauben, dass das funktionieren könnte? :) Wenn Sie 'f()' mit einer beliebigen Anzahl von Parametern aufrufen, erhalten Sie einen 'TypeError'. –

+0

@TimPietzcker naja, es funktioniert *, aber S/O hat sich plötzlich entschieden, viele Updates auf mich zu werfen - die, wenn sie gelesen werden, diese Antwort im Kontext der OP-Frage –

Verwandte Themen