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

时间:2017-05-16 10:39:34

标签: 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

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

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

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

我猜这样做是为了让API更加用户友好,但是我没有找到任何支持它的资源(源代码并没有多说明,PEP 457只说明{ {1}}很奇怪)。有谁知道为什么这样做了?

1 个答案:

答案 0 :(得分:6)

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

  

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

它是用C实现的,但行为不是“Pythonland”中的违规行为。文档中的签名是不正确的(实际上不正确,它是“真实签名”的近似 - 可以很容易理解)。

例如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)可能略有不同,所以不要认真对待这个类。)

然而,像range(*args)这样的签名可能对用户(特别是甚至不知道*args意味着什么的新用户)可能没什么帮助。如果文档中显示range有2个签名:range(stop)range(start, stop[, step])可能不(技术上)准确,但它“解释”签名的解释方式。

至于为什么:我没有任何可靠的来源,但我很快就扫描了我的代码:

我比range(stop)range(start, stop)更频繁地使用range(start, stop, step)。因此,一个论证案例可能特殊且足够常见以便于它。总是在整个地方写range(0, stop)会非常烦人。