Как функция диапазона Python имеет параметр по умолчанию перед фактическим?
Итак, я пишу функцию, которая принимает дополнительный список и расширяет его до указанной длины. Вместо того, чтобы писать его как foo (n, list = None), мне было интересно, как я могу эмулировать поведение функции диапазона Python, которая работает следующим образом:
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> range(5, 10)
[5, 6, 7, 8, 9]
То есть с параметром по умолчанию. Для справки, пытающейся наивно установить это, возвращается синтаксическая ошибка:
def foo(x=10, y):
return x + y
SyntaxError: non-default argument follows default argument
Так что мне интересно, это жестко закодировано в диапазоне? Или можно эмулировать такое поведение?
Ответы
Ответ 1
Они не являются аргументами реального ключевого слова.
Если есть один аргумент, это предел.
Если есть два аргумента, первым является начальное значение, а второе - предел.
Если есть три аргумента, первое - начальное значение, второе - предел, а третий - шаг.
Ответ 2
Один способ написать range
в чистом python будет
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
Ответ 3
Другие показали, как это можно сделать, используя подсчет аргументов. Если бы я сам реализовал его на Python, я бы сделал это более как это.
def range(start, limit=None, stride=1):
if limit is None:
start, limit = 0, start
# ...
Ответ 4
Python реализует range()
, просматривая количество аргументов. Не стоит слишком писать питонную версию этого кода
from 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;
}
Ответ 5
Рассмотрим:
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)