Douwe van der Leest
Douwe van der Leest

Reputation: 95

Order of range() arguments in python

I am wondering how the range() function in Python 2.7 is able to have a syntax like:

range(start, stop[, step])

As creating a function in Python requires the optional arguments to be at the end of the parameter entries, as in:

function(a, b, c=1)

(for some reason I can't find the file in which range() is declared so...) But it is possible to enter only a single (stop) integer as in range(10)

Does range then use some construct like the one below? Or is there a more elegant way to do this?

def TestRange(start, stop = None, stepSize = 1):
    if stop == None:
        d = 0
        TrackTest = []
        while d < start:
            TrackTest += [d]
            d += stepSize
        return TrackTest
    else:
        d = start
        TrackTest = []
        while d < stop:
            TrackTest += [d]
            d += stepSize
        return TrackTest

Using the test cases below we get a (seemingly) similar result as that of using a range function.

print TestRange(6)
print TestRange(2, 6)
print TestRange(2, 6, 2)

Upvotes: 1

Views: 604

Answers (1)

szym
szym

Reputation: 5846

Take a look at the source code for range (this is the range_new function): https://github.com/python/cpython/blob/d741c6d3179b771cec8d47c7b01dd48181b7717e/Objects/rangeobject.c#L79

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;
    }
}

It is essentially the same approach as in your TestRange, although you can do TestRange(stop, step=3) but you can't do range(stop, step=3), because the last argument to range is not actually a keyword arg.

Upvotes: 2

Related Questions