17

range 函数如何采用:单个参数、range(stop)、 或range(start, stop)、 或range(start, stop, step)。它是否使用variadic诸如*arg收集参数之类的参数,然后根据提供的参数数量使用一系列 if 语句来分配正确的值?本质上,确实range()指定如果有一个参数,则将其设置为停止参数,或者如果有两个,则它们是start, 和stop,或者如果有三个则将它们分别设置为stop,startstep?我想知道如果要在纯 CPython 中编写 range 将如何做到这一点。

4

4 回答 4

7

Range 采用 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.

于 2012-11-13T18:16:43.220 回答
6

开源软件的美妙之处在于您可以在源代码中查找它

(TL;DR:是的,它使用可变参数)

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;
    }
}
于 2012-11-13T18:22:28.183 回答
4

lqc 的回答演示了如何在 C中实现。如果 Python 的内置函数是用 Python 编写的,range您可能仍然对如何实现感到好奇。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使用一个、两个或三个参数进行调用。如何解释每个参数取决于提供了多少参数。

于 2012-11-13T18:57:24.587 回答
0

xrangeIterator 类:

def __init__(self,xrange_obj):

    self._xrange_obj=xrange_obj


def __next__(self):

    self.copy_gen=self._xrange_obj._result

    for i in self.copy_gen:

        return i

    raise StopIteration

xrange 类:

def __init__(self,*args):

    self._args=args

    self.start,self.step=0,1

    self._repr_string=None

    for i in self._args:

        if type(i) is not int:

            raise TypeError("Cannot interprate '{}' as integer!".format(type(i).__name__))


    if self._length(self._args)<1:

        raise TypeError( "xrange Must have at least one argument")


    elif self._length(self._args)==1:

        self.stop=self._args[0]

        self._repr_string="xrange(0,{})".format(self.stop)

        self._result=self._xrange(self.start-self.step,self.stop-self.step,self.step)

    elif self._length(self._args)==2:

        self.start=self._args[0]

        self.stop=self._args[1]

        self._result=self._xrange(self.start-self.step,self.stop-self.step,self.step)

    elif self._length(self._args)==3:

        self.step=self._args[2]

        self.start=self._args[0]

        self.stop=self._args[1]

        self._result=self._xrange(self.start-self.step,self.stop-self.step,self.step)


    else:

        raise TypeError("xrange expected at most three arguments,got {}".format(self._length(self._args)))


def __repr__(self):

    if self._length(self._args)==1:

        return self._repr_string

    return "xrange{}".format(self._args)

def __iter__(self):

    return xrangeIterator(self)


def _length(self,n):

    counter=0

    for i in n:

        counter+=1

    return counter


def _xrange(self,start,stop,step):

    if step==0:

            raise ValueError("Argument 3 should not be zero!")

    if start<stop and step<0:

            raise TypeError("argument 3 should not be {}".format(step))

    if start<stop:

        while start<stop:

            start+=step

            yield start

    else:

        while start>stop and step<0:

            start+=step

            yield start
于 2019-04-09T17:38:49.167 回答