内置范围函数如何只需一个参数或三个参数?

时间:2012-11-13 18:12:28

标签: python function arguments range

我想知道,如果有人可以告诉我,范围函数如何能够采用:单个参数range(stop)range(start, stop)range(start, stop, step)。它是否使用variadic参数(如*arg来收集参数,然后使用一系列if语句根据提供的参数数量分配正确的值?实质上,range()是否指定如果有一个参数,则将其设置为停止参数,或者如果有两个参数,那么它们是startstop,或者如果有然后将它们分别设为stopstartstep?我想知道如果要在纯Cpython中编写范围,人们会怎么做。感谢!!!

更新: 当我最初问这个问题时,我没有澄清,我想知道Cpython中的答案。无论如何,谢谢你的回复!我发现它们都很有启发性。这种反馈让我喜欢stackoverflow和让它如此特别的人!

4 个答案:

答案 0 :(得分:5)

开源软件的美妙之处在于你可以just look it up in the source

(TL; DR:是的,它使用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;
    }
}

答案 1 :(得分:4)

范围包含1个,2个或3个参数。这可以使用def range(*args)实现,以及在获得0或3个​​以上参数时引发异常的显式代码。

无法使用默认参数实现,因为在默认情况下您不能使用非默认值,例如def range(start=0, stop, step=1)。这主要是因为python必须弄清楚每个调用的含义,所以如果你用两个参数调用,python需要一些规则来确定你覆盖哪个默认参数。不是这样的规则,而是根本不允许的。

如果您确实想使用默认参数,可以执行以下操作:def range(start=0, stop=object(), step=1)并明确检查stop的类型。

答案 2 :(得分:2)

lqc's answer演示了如何在C中实现range。如果Python的内置函数是用Python编写的,那么你可能仍然会对如何实现range感到好奇。我们可以阅读PyPy的源代码来查找。来自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

第一个参数space在我看到的所有内置函数中都显示为参数,所以我猜它有点像self,因为用户不直接提供它。在剩余的三个参数中,其中两个具有默认值;所以你可以用一个,两个或三个参数调用range。每个参数的解释方式取决于提供的参数数量。

答案 3 :(得分:0)

python 2 xrange()的简单实现。完全相同。

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 start<stop:
            start+=(step)
            lst1.append(start)

        return lst1

    if len(args)==2:
        start=(args[0]-step)
        stop=(args[1]-step)

        while start<stop:
            start+=(step)
            lst1.append(start)

        return lst1

    if len(args)==3:
        step=args[2]

        if step==0:
            return "Argument 3 should not be zero!"

        start=(args[0]-(step))
        stop=(args[1]-(step))

        if start<stop:
            while start<stop:
                if start<stop:
                    start+=step
                    lst1.append(start)
        else:
            while start>stop and step<0:
                start+=step
                lst1.append(start)

        return lst1

    if length(args)>3:
        return "Expected at most three arguments,got {}".format(len(args))