2010-11-09 20 views
14

In Python, capisco che gli argomenti predefiniti arrivano alla fine e che gli argomenti non predefiniti non possono seguire un argomento predefinito. Questo va bene. Ad esempio:Ordine di default e argomenti non predefiniti

>>> def foo(x=0, y): 
     return x, y 
SyntaxError: non-default argument follows default argument 

OK come previsto.

Tuttavia, che dire del caso in cui voglio che il primo argomento sia uno predefinito? Come per esempio, come risulta dal codice precedente, x deve essere il primo argomento e dovrebbe avere un valore predefinito di 0.

È possibile farlo? Chiedo perché anche nella funzione range, sto indovinando è qualcosa di simile:

def range(start=0, end): 
    pass 

Così come è questo fatto e se non è possibile, come è questo implementata da range? Nota che sto insistendo sul fatto che il primo argomento sia il default, cioè l'intero punto. Sto usando range come esempio perché si adatta perfettamente al mio problema. Naturalmente si potrebbe implementare range come def range(end, start=0), ma non è questo il punto.

risposta

9

Beh, range è il codice C che può fare questo un po 'meglio. In ogni caso, è possibile effettuare questa operazione:

def range(start, stop=None): 
    if stop is None: # only one arg, treat stop as start ... 
     stop = start 
     start = 0 
    ... 

e documentare la funzione di conseguenza.

+1

Quasi identico alla mia risposta, ma più chiaro e cinque minuti prima. Quindi, +1. –

+0

Potrebbe voler aggiungere un argomento 'step' per coerenza con built-in. –

+0

+1. È perfetto. Mi sento stupido a non pensarci. – user225312

1

È possibile gestire le eccezioni da soli se si vuole veramente che

def Range(start=0, end=None): 
    if end is None: 
     raise AttributeError("end value not specified") 
    pass 
2

Non è implementato da range. È possibile utilizzare *args o **args e trattare la tupla o il dict come si desidera. Ad esempio:

 
def f(*args): 
    if len(args) == 1: 
    print "assuming the first is default" 
    elif len(args) == 2: 
    print "two arguments were passed" 
    else: 
    print "Complaining" 

2

Ci sono un paio di approcci. Il primo sarebbe quello di cambiare gli argomenti nella funzione, se alcuni degli argomenti sono "Nessuno". Funzionerebbe così.

def range1(value, end=None): 
    if end == None: 
     end = value 
     value = 0 
    return _generate_range_values(value, end) 

L'altro metodo principale sarebbe quello di avere la funzione ottenere un elenco di tutti gli argomenti che riceve. Quindi può decidere cosa fare, in base al numero di argomenti.

def range2(*args): 
    if len(args) == 1: 
     start = 0 
     end = int(args[0]) 
    elif len(args) == 2: 
     start = int(args[0]) 
     end = int(args[1]) 
    return _generate_range_values(start, end) 

Il terzo sarebbe incoraggiare gli utenti a passare argomenti denominati alla funzione, il che rende l'ordine meno importante.

def range3(end, start=0): 
    return _generate_range_values(start, end) 

Poi utenti avrebbero chiamato con l'argomento start chiamato quando volevano qualcosa oltre 0. (Anche se l'argomento di nome non sarebbe stato necessario, mantiene il codice chiaro.

for i in range3(55, start=12) 
+0

+1 Anche se non capisco perché hai sentito il bisogno di usare 'int()' su 'args [x]' in 'range2()' ma non negli altri. Non è necessario (anche se consente a quella versione di accettare argomenti in virgola mobile e stringa come '3.14' e' "42" '). – martineau

+0

Guardando indietro, non sono sicuro del perché ho usato int() in uno degli esempi e non in altri. La funzione built-in range() genera un errore se ottiene qualcosa oltre agli argomenti interi. –

1

I don' t hanno il codice per la gamma, ma sono certo che esegue questo tipo di trucco:

def range(start, stop=None, step=1): 
    if stop is None: 
     start, stop = 0, start 
    ... 

edit: codice corretto per il commento di Martineau.

Problemi correlati