2012-09-04 22 views
8

Szukam naśladowania zachowania wbudowanych funkcji (takich jak getattr), które pozwalają użytkownikowi określić "domyślną" wartość zwracaną. Moja Pierwsza próba była to zrobićpython - zwracanie wartości domyślnej

def myfunc(foo, default=None): 
    # do stuff 
    if (default is not None): 
     return default 
    raise SomeException() 

Problemem jest to, że jeśli użytkownik chce None być ich wartości zwracanej, funkcja ta będzie zamiast podnieść wyjątek. Druga próba:

def myfunc(foo, **kwargs): 
    # do stuff 
    if ('default' in kwargs): 
     return kwargs['default'] 
    raise SomeException() 

To rozwiązuje powyższy problem i pozwala użytkownikowi określić dowolną wartość, ale wprowadza irytacji tym, że użytkownik musi zawsze określić default=bar w nazywa ich funkcję; nie mogą po prostu dostarczyć bar na końcu. Podobnie może być użyty *args, ale uniemożliwia użytkownikom korzystanie z default=bar, jeśli wolą tę składnię.

Łączenie *args i **kwargs stanowi praktyczne rozwiązanie, ale wydaje się, że będzie to wymagało wiele wysiłku. Maski również potencjalnie niewłaściwe wywołania funkcji (np bar = myfunc(foo, baz, default=qux))

def myfunc(foo, *args, **kwargs): 
    # do stuff 
    if (len(args) == 1): 
     return args[0] 
    if ('default' in kwargs): 
     return kwargs['default'] 
    raise SomeException() 

Czy istnieje prostsze rozwiązanie? (Python 3.2, czy to ma znaczenie)

Odpowiedz

14

Musisz użyć Sentinel wykryć, że wartość domyślna nie została ustawiona:

sentinel = object() 

def func(someparam, default=sentinel): 
    if default is not sentinel: 
     print("You passed in something else!") 

To działa, ponieważ wystąpienie object() zawsze będzie mieć swój własny identyfikator pamięci, a tym samym is zwróci tylko wartość True, jeśli dokładna wartość pozostała na miejscu. Każda inna wartość nie zostanie zarejestrowana jako ten sam obiekt, w tym None.

Zobacz różne warianty powyższej sztuczki w różnych różnych projektach Pythona. Dowolny z poniższych wskaźników może również zadziałać:

sentinel = [] 
sentinel = {} 
+0

To jest o wiele prostsze, dzięki! – Steve

+0

Czy istnieje jednak sposób, aby zatrzymać ludzi przechodzących w wartownika? –

+2

@hayden: oczywiście, że nie, to jest pyton. Zwykle nazywasz go '_sentinel' lub podobnym, aby oznaczyć go jako prywatny, ale to nie powstrzymuje wszystkich przedsiębiorczych dusz od zerwania wszystkiego przez zaimportowanie go. Oczywiście nie ma sensu tego robić. –

Powiązane problemy