17

範囲関数はどのようにして次のいずれかを取ることができますか: 単一の引数、、range(stop)またはrange(start, stop)、またはrange(start, stop, step)variadic引数を収集するような引数を使用して*argから、一連の if ステートメントを使用して、指定された引数の数に応じて正しい値を割り当てますか? 本質的に、range()引数が 1 つある場合は停止引数として設定するか、2 つある場合はstart、およびstop、または 3 つある場合はそれらをそれぞれstopstart、およびとして設定することを指定しstepますか? 純粋な CPython で範囲を記述する場合、これをどのように行うかを知りたいです。

4

4 に答える 4

7

範囲は、1、2、または3つの引数を取ります。これは、、および明示的なコードを使用して実装しdef range(*args)、0個または3個を超える引数を取得したときに例外を発生させることができます。

デフォルトの後にデフォルト以外の値を設定することはできないため、デフォルトの引数を使用して実装することはできませんでしたdef range(start=0, stop, step=1)。これは基本的に、Pythonが各呼び出しの意味を理解する必要があるためです。したがって、2つの引数を使用して呼び出す場合、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どのように実装されるかについてまだ興味があるかもしれません。rangePyPy のソース コードを読んで確認できます。から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、ユーザーが直接指定しないという点で似ていると思います。残りの 3 つの引数のうち、2 つにはデフォルト値があります。rangeそのため、1 つ、2 つ、または 3 つの引数で呼び出すことができます。各引数がどのように解釈されるかは、指定された引数の数によって異なります。

于 2012-11-13T18:57:24.587 に答える