范围非默认参数遵循默认参数

range non-default parameter follows default one

为什么 range 允许非默认参数 (stop) 跟随 默认参数 (start)?

例证:

>>> r = range(1, 2, 3)
>>> print(r.start, r.stop, r.step)
1 2 3
>>> r = range(10)
>>> print(r.start, r.stop, r.step)
0 10 1

试图模仿签名是明显的违规行为:

def my_range(start=0, stop, end=1):
    pass

我知道它在 C 中实现的事实可能允许在 Pythonland 中出现违规行为。

我猜这样做是为了让 API 对用户更友好,但是,我没有找到任何支持它的来源(源代码并没有说明什么 PEP 457 仅说明 range 是奇数)。有谁知道为什么这样做?

我认为这个问题的前提是错误的:

I understand that the fact it is implemented in C probably allows for behavior that would be a violation in Pythonland.

它是用 C 语言实现的,但该行为并不违反 "Pythonland"。文档中的签名只是不正确(实际上不是不正确,它是 "real signature" 的近似值 - 这很容易理解)。

例如 range 甚至不支持命名参数 - 但根据文档它应该:

>>> range(stop=10)
TypeError: range() does not take keyword arguments

所以实现更多的是:

class range(object):
    def __init__(self, *args):
        start, step = 0, 1
        if len(args) == 1:
            stop = args[0]
        elif len(args) == 2:
            start, stop = args
        elif len(args) == 3:
            start, stop, step = args

这是有效的 Python 并且(大致)做了 range 内部所做的事情(actual implementation (CPython, Python 3.6.1) 可能略有不同所以不要把 class 当回事) .

然而,像 range(*args) 这样的签名可能对用户没有真正的帮助(尤其是甚至不知道 *args 是什么意思的新用户)。有一份文件说 range 有 2 个签名:range(stop)range(start, stop[, step]) 可能(技术上)不准确,但 "explains" 如何解释签名。


至于原因:我没有任何可信的来源,但我很快扫描了我的代码:

我使用 range(stop) 的频率远高于 range(start, stop)range(start, stop, step)。因此,单参数案例可能 足够特殊和常见 以方便使用。总是到处写 range(0, stop) 会很烦人。