¿Cómo tiene la función de rango de Python un parámetro predeterminado antes del real?

Así que estoy escribiendo una función que toma una lista opcional y la extiende a la longitud especificada. En lugar de escribirlo como foo (n, list = None) me preguntaba cómo podría emular el comportamiento de la función de rango de Python, que funciona como:

>>> range(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> range(5, 10) [5, 6, 7, 8, 9] 

Es decir, con el parámetro por defecto primero. Como referencia, intentar configurar esto de forma ingenua devuelve un error de syntax:

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

Así que me pregunto, ¿está esto codificado dentro del rango? ¿O se puede emular este comportamiento?

No son argumentos de palabras clave reales.

Si hay un argumento, es el límite.

Si hay dos argumentos, el primero es el valor de inicio y el segundo es el límite.

Si hay tres argumentos, el primero es el valor de inicio, el segundo es el límite y el tercero es el paso.

Otros han mostrado cómo se puede hacer usando el conteo de argumentos. Sin embargo, si lo implementara yo mismo en Python, lo haría más así.

 def range(start, limit=None, stride=1): if limit is None: start, limit = 0, start # ... 

Una forma de escribir range en python puro sería

 def range(*args): if len(args) > 3: raise TypeError, 'range expected at most 3 arguments, got %d' % len(args) if len(args) == 2: return range(args[0], args[1], 1) if len(args) == 1: return range(0, args[0], 1) else: # actual code for range(start, stop, step) here 

Python implementa el range() mirando el número de argumentos. No debería ser demasiado difícil escribir una versión de Python de este código

de rangeobject.c:

 static PyObject * range_new(PyTypeObject *type, PyObject *args, PyObject *kw) { rangeobject *obj; long ilow = 0, ihigh = 0, istep = 1; unsigned long n; if (!_PyArg_NoKeywords("xrange()", kw)) return NULL; if (PyTuple_Size(args) <= 1) { if (!PyArg_ParseTuple(args, "l;xrange() requires 1-3 int arguments", &ihigh)) return NULL; } else { if (!PyArg_ParseTuple(args, "ll|l;xrange() requires 1-3 int arguments", &ilow, &ihigh, &istep)) return NULL; } if (istep == 0) { PyErr_SetString(PyExc_ValueError, "xrange() arg 3 must not be zero"); return NULL; } n = get_len_of_range(ilow, ihigh, istep); if (n > (unsigned long)LONG_MAX || (long)n > PY_SSIZE_T_MAX) { PyErr_SetString(PyExc_OverflowError, "xrange() result has too many items"); return NULL; } obj = PyObject_New(rangeobject, &PyRange_Type); if (obj == NULL) return NULL; obj->start = ilow; obj->len = (long)n; obj->step = istep; return (PyObject *) obj; } 

Considerar:

 def f(*args): nargs = len(args) if nargs == 1: start = 0 end = args[0] step = 1 elif nargs == 2: start = args[0] end = args[1] step = 1 elif nargs == 3: start = args[0] end = args[1] step = args[2] else: raise TypeError('wrong number of arguments') return g(start, end, step)