2013-06-06 13 views
5

Potrzebuję funkcji z domyślnymi argumentami, które muszą być ustawione w czasie działania funkcji (takie jak puste listy, wartości pochodne od innych argumentów lub danych pobranych z bazy danych) i obecnie używam następujący wzór, aby sobie z tym poradzić:Dynamiczne domyślne argumenty w funkcjach Pythona

def foo(bar, baz=None): 
    baz = baz if baz else blar() 
    # Stuff 

Gdzie blar() daje odpowiednią wartość domyślną baz co może zmienić w trakcie realizacji. Jednak linia baz = baz if baz else ... uderza mnie jako nieelegancką. Czy ktokolwiek inny ma lepszą metodę unikania jednorazowego wiązania domyślnych argumentów funkcji? Małe, wieloplatformowe biblioteki instalowane przez pip to akceptowalne zamienniki.

Odpowiedz

8

Nie, to prawie wszystko. Zazwyczaj przetestować is None więc można bezpiecznie przejść w wartościach falsey jak 0 lub "" itp

def foo(bar, baz=None): 
    baz = baz if baz is not None else blar() 

staroświecki sposób jest dwa liner. Niektórzy ludzie mogą preferować ten

def foo(bar, baz=None): 
    if baz is None: 
     baz = blar() 
+3

Staromodny sposób pozwala uniknąć niepotrzebnego przypisania, gdy 'baz' nie jest' Brak'. – chepner

0

Szybka & brudny przykładową implementację czegoś, co może zadziałać:

class DynDefault(object): 
    def __init__(self, callback): 
     self.callback = callback 
    def __call__(self): 
     return self.callback() 

def dyn_default(func): 
    def wrapper(*args, **kw): 
     args = [arg() for arg in args if isinstance(arg, DynDefault) else arg] 
     for k, v in kw.items(): 
      if isinstance(v, DynDefault): 
       kw[k] = v() 
     return func(*args, **kw) 
    return wrapper 

@dyn_default 
def foo(bar, baaz=DynDefault(blar)): 
    # problem solved 
+0

To rozwiązanie jest zepsute. Przetwarzając argumenty, nie leniwy ocenisz dynamiczne domyślne argumenty, ale wszelkie możliwe 'DynDefault' dostarczone, gdy faktycznie wywołasz funkcję. Praktycznym rozwiązaniem może być zamiana 'foo.func_defaults' na obiekt deskryptora, jednak func_defaults może być tylko krotką. Chociaż podklasowanie krotki i przeciążanie __iter__ i __getitem__ może utrzymać nas w grze, niewielka analiza źródła CPython ujawnia, że ​​członkowie obiektu 'func_defaults' są udostępniani bezpośrednio w pamięci w PyObject, a nie w interfejsie klasy newstyle, dlatego też nie można rozwiązać. :( –

1

Można zastąpić

baz = baz if baz else blar() 

z

baz = baz or blar() 

, jeśli nadal jesteś zadowolony z testowania wartości falsy zamiast None.

Powiązane problemy