How does the Python range function have a default parameter before the actual one?

爱⌒轻易说出口 提交于 2019-11-29 12:41:09

问题


So I'm writing a function that takes an optional list and extends it to the length specified. Rather than writing it as foo(n, list=None) I was wondering how I might emulate the behavior of Python's range function which works like:

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

That is, with the default parameter first. For reference trying to naively set this up returns a syntax error:

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

So I'm wondering, is this hard-coded into range? Or can this behavior be emulated?


回答1:


They aren't real keyword arguments.

If there's one argument, it's the limit.

If there are two arguments, the first is the start value and the second is the limit.

If there are three arguments, the first is the start value, the second is the limit, and the third is the stride.




回答2:


Others have shown how it can be done using argument counting. If I were to implement it myself in Python, though, I'd do it more like this.

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



回答3:


One way to write range in pure python would be

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



回答4:


Python implements range() by looking at the number of arguments. It shouldn't be too hard to write a Python version of this code

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:


Consider:

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)


来源:https://stackoverflow.com/questions/6644537/how-does-the-python-range-function-have-a-default-parameter-before-the-actual-on

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!