为什么范围允许非默认参数(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}}很奇怪)。有谁知道为什么这样做了?
答案 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)
会非常烦人。