2010-11-09 9 views
14

En Python, entiendo que los argumentos predeterminados vienen al final y que los argumentos no predeterminados no pueden seguir un argumento predeterminado. Eso está bien. Como por ejemplo:Orden de argumentos predeterminados y no predeterminados

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

Eso está bien como se esperaba.

Sin embargo, ¿qué pasa con el caso cuando quiero que el primer argumento sea uno predeterminado? Como por ejemplo, como se desprende del código anterior, x tiene que ser el primer argumento y debe tener un valor predeterminado de 0.

¿Es posible hacer esto? Me pregunto porque incluso en la función range, que supongo que es algo como esto:

def range(start=0, end): 
    pass 

Entonces, ¿cómo se hace esto y si no es posible, ¿cómo se implementa range? Tenga en cuenta que insisto en que el primer argumento sea el predeterminado, es decir, todo el punto. Estoy usando range como ejemplo porque encaja perfectamente con mi problema. Por supuesto, uno podría implementar range como def range(end, start=0), pero ese no es el punto.

Respuesta

9

Bueno, range es código C que puede hacerlo un poco mejor. De todos modos, puede hacer esto:

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

y documentar la función en consecuencia.

+1

Casi idéntico a mi respuesta, pero más claro y cinco minutos antes. Entonces, +1. –

+0

Podría querer agregar un argumento 'step' para coherencia con el built-in. –

+0

+1. Eso es perfecto. Me siento estúpido sin pensar en esto. – user225312

1

Puede manejar las excepciones si realmente quiere que

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

No está implementado por range. Puede usar *args o **args y tratar la tupla o el dict como lo desee. Por ejemplo:

 
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

Hay un par de enfoques. El primero sería cambiar los argumentos en la función, si algunos de los argumentos son "Ninguno". Eso funcionaría así.

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

El otro método principal sería que su función obtenga una lista de todos los argumentos que recibe. Luego puede decidir qué hacer, en función del número de argumentos.

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) 

La tercera sería alentar a los usuarios a pasar argumentos con nombre a su función, lo que hace que el orden sea menos importante.

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

A continuación, los usuarios podrían llamarlo con el argumento de arranque llamada cuando querían algo más que 0. (Aunque no se requeriría el argumento con nombre, se mantiene el código claro.

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

+1 Aunque no entiendo por qué sentiste la necesidad de usar 'int()' en 'args [x]' en 'range2()' pero no en los demás. No es necesario (aunque permite que esa versión acepte argumentos de punto flotante y de cadena como '3.14' y' '42" '). – martineau

+0

Mirando hacia atrás, no estoy seguro de por qué usé int() en uno de los ejemplos y no en otros. La función de rango incorporado() generará un error si obtiene algo además de los argumentos enteros. –

1

I don' t tiene el código para la gama, pero estoy seguro de que realiza este tipo de truco:

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

edición: código corregido por el comentario de Martineau.

Cuestiones relacionadas