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

Jim*_*ard 9 python python-3.x python-internals

为什么范围允许非默认参数(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
Run Code Online (Sandbox Code Playgroud)

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

def my_range(start=0, stop, end=1):
    pass
Run Code Online (Sandbox Code Playgroud)

我知道它实现的事实C可能允许在Pythonland中违反的行为.

我猜这是为了使API更加用户友好,但我没有找到任何来源备份它(源代码并没有说明多少,而PEP 457只说明了多么range奇怪).有谁知道为什么这样做了?

MSe*_*ert 7

我认为问题是基于一个错误的前提:

我理解它在C中实现的事实可能允许在Pythonland中违反的行为.

它是用C实现的,但这种行为并不违反"Pythonland".文档中的签名是不正确的(实际上不正确,它是"真实签名"的近似 - 可以很容易理解).

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

>>> range(stop=10)
TypeError: range() does not take keyword arguments
Run Code Online (Sandbox Code Playgroud)

所以实施更多的是:

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
Run Code Online (Sandbox Code Playgroud)

这是有效的Python和(大致)range内部做的事情(实际的实现(CPython,Python 3.6.1)可能会略有不同,所以不要认真对待这个类).

然而,签名之类range(*args)的用户可能并不真正有用(特别是那些甚至不知道具体*args含义的新用户).有了这样说,一个文件range有2个特征:range(stop)range(start, stop[, step])可能不是(在技术上)准确,但"解释"的签名是如何解释.


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

range(stop)经常使用range(start, stop)或比range(start, stop, step).因此,一个论证案例可能是特殊的,并且足以为它提供便利.总是range(0, stop)在整个地方写作会很烦人.

  • 实用性确实超越了纯洁.谢谢你的写作; 我会在接下来的几天里更彻底地研究这个问题,如果发现任何奇怪的事情我会回来. (2认同)