¿Cómo puede la función de rango incorporada tomar un solo argumento o tres?

Me gustaría saber, si alguien me puede decir, cómo la función de rango puede tomar ya sea un solo argumento, range(stop) o range(start, stop) o range(start, stop, step) . ¿Utiliza un argumento variadic como *arg para recostackr los argumentos y luego utiliza una serie de sentencias if para asignar los valores correctos en función del número de argumentos proporcionados? En esencia, el range() especifica que si hay un argumento, entonces se establece como el argumento de parada, o si hay dos, entonces se start , y se stop , o si hay tres, se establecen como stop , start , y step respectivamente? Me gustaría saber cómo se haría esto si se escribiera el rango en Cpython puro. ¡¡¡Gracias!!!

Actualización : no aclaré, cuando inicialmente hice la pregunta, que quería saber la respuesta en Cpython. En cualquier caso, gracias por todas sus respuestas! Los encontré a todos bastante esclarecedores. ¡Este es el tipo de comentarios que me hacen amar el stackoverflow y la gente que lo hace tan especial!

El rango toma, 1, 2 o 3 argumentos. Esto podría implementarse con def range(*args) y código explícito para generar una excepción cuando obtiene 0 o más de 3 argumentos.

No se pudo implementar con argumentos predeterminados porque no puede tener un valor no predeterminado después de un valor predeterminado, por ejemplo, def range(start=0, stop, step=1) . Esto se debe esencialmente a que Python tiene que averiguar qué significa cada llamada, por lo tanto, si tuviera que llamar con dos argumentos, Python necesitaría alguna regla para determinar qué argumento predeterminado estaba anulando. En lugar de tener tal regla, simplemente no está permitido.

Si quisiera usar argumentos predeterminados, podría hacer algo como: def range(start=0, stop=object(), step=1) y realizar una comprobación explícita del tipo de stop .

La belleza del software de código abierto es que puede buscarlo en la fuente :

(TL; DR: sí, utiliza varargs)

 if (PyTuple_Size(args) <= 1) { if (!PyArg_UnpackTuple(args, "range", 1, 1, &stop)) return NULL; stop = PyNumber_Index(stop); if (!stop) return NULL; start = PyLong_FromLong(0); if (!start) { Py_DECREF(stop); return NULL; } step = PyLong_FromLong(1); if (!step) { Py_DECREF(stop); Py_DECREF(start); return NULL; } } else { if (!PyArg_UnpackTuple(args, "range", 2, 3, &start, &stop, &step)) return NULL; /* Convert borrowed refs to owned refs */ start = PyNumber_Index(start); if (!start) return NULL; stop = PyNumber_Index(stop); if (!stop) { Py_DECREF(start); return NULL; } step = validate_step(step); /* Caution, this can clear exceptions */ if (!step) { Py_DECREF(start); Py_DECREF(stop); return NULL; } } 

La respuesta de lqc demuestra cómo se implementa el range en C. Es posible que todavía tenga curiosidad acerca de cómo se implementaría el range si las funciones incorporadas de Python se escribieran en Python. Podemos leer el código fuente de PyPy para averiguarlo. Desde pypy/module/__builtin__/functional.py :

 def range_int(space, w_x, w_y=NoneNotWrapped, w_step=1): """Return a list of integers in arithmetic position from start (defaults to zero) to stop - 1 by step (defaults to 1). Use a negative step to get a list in decending order.""" if w_y is None: w_start = space.wrap(0) w_stop = w_x else: w_start = w_x w_stop = w_y 

El primer argumento, space , aparece como un argumento en todas las funciones integradas que vi, así que supongo que es algo así como que el usuario no lo proporciona directamente. De los tres argumentos restantes, dos de ellos tienen valores por defecto; para que pueda llamar a range con uno, dos o tres argumentos. Cómo se interpreta cada argumento depende de cuántos argumentos se suministraron.

Una implementación simple de python 2 xrange() . Funciona exactamente igual.

 def xrange(*args): start,step=-1,1 lst1=[] for i in args: if type(i) is not int: return "Cannot interprate '{}' as integer!".format(type(i).__name__) if len(args)<1: return "c_range Must have at least one argument" if len(args)==1: stop=(args[0]-step) while startstop and step<0: start+=step lst1.append(start) return lst1 if length(args)>3: return "Expected at most three arguments,got {}".format(len(args))