如何使用签名([start,] stop [,step])实现python方法,即左侧的默认关键字参数

Raf*_*l T 4 python arguments method-signature python-3.x

因为在python 3.X中,build-id range()函数不再返回一个列表而是一个可迭代的,一些旧的代码失败,因为我用它range()来方便地生成我需要的列表.

所以我尝试实现我自己的lrange功能:

def lrange(start = 0, stop, step = 1):
    ret = []
    while start < stop:
        ret.append(start)
        start += step
    return ret
Run Code Online (Sandbox Code Playgroud)

给我一个"非默认参数遵循默认参数"解释器错误.

如果我看看Python的范围()似乎是可能的.

我发布这个问题主要是因为我想知道是否/如何自己实现具有这种签名的功能

Aar*_*all 9

快速回答

当我第一次开始学习Python时出现了这个问题,我认为在这里记录这个方法是值得的.只有一个检查用于模拟原始行为.

def list_range(start, stop=None, step=1):
    if stop is None:
         start, stop = 0, start
    return list(range(start, stop, step))
Run Code Online (Sandbox Code Playgroud)

我认为这个解决方案比使用所有关键字参数或者更优雅*args.

说明

使用Sentinel

获得此权利的关键是使用sentinel对象来确定是否获得第二个参数,如果没有,则在将第一个参数移动到第二个参数时将默认值提供给第一个参数.

None,作为Python的空值,是一个很好的最佳实践哨兵,检查它的惯用方法是使用关键字is,因为它是一个单例.

带有正确文档字符串的示例,声明签名/ API

def list_range(start, stop=None, step=1):
    '''
    list_range(stop) 
    list_range(start, stop, step)

    return list of integers from start (default 0) to stop,
    incrementing by step (default 1).

    '''
    if stop is None:
         start, stop = 0, start
    return list(range(start, stop, step))
Run Code Online (Sandbox Code Playgroud)

示范

>>> list_range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list_range(5, 10)
[5, 6, 7, 8, 9]
>>> list_range(2, 10, 2)
[2, 4, 6, 8]
Run Code Online (Sandbox Code Playgroud)

如果没有给出参数,它会引发错误,这与全关键字解决方案不同.

警告

顺便说一下,我希望这只是从读者的理论角度考虑,我不相信这个功能值得维护,除非在中心规范位置使用,使代码在Python 2和3之间交叉兼容. Python,使用内置函数将范围具体化为列表非常简单:

Python 3.3.1 (default, Sep 25 2013, 19:29:01) 
[GCC 4.7.3] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Run Code Online (Sandbox Code Playgroud)


dsk*_*ner 5

我从来没有真正考虑过这个问题,但首先,为了解决你的问题,你应该能够在你的代码中用list(range(...))包装range(...).

使用关键字参数,您可以实现类似的签名,因为在调用时不需要指定实际的键

def f(x=None, y=None, z=None):
    print x, y, z

f(1, 2, 3)
#output: 1 2 3
Run Code Online (Sandbox Code Playgroud)

然后,您可以检查值以确定应如何处理它们.所以要模仿范围

def f(x=None, y=None, z=None):
    if z is not None: # then all values were assigned
        return range(x, y, z)
    elif y is not None: # then a start stop was set
        return range(x, y):
    else: # only one value was given
        return range(x)
Run Code Online (Sandbox Code Playgroud)

这里的要点不是作为范围的包装器(如上所述,只是使用列表),而是要提供一些洞察力,确定是否真的试图模仿自定义内容范围的内置范围签名.

另外请记住,这不是一个完整的解决方案,f(z=1)可能会导致上述问题,因此您希望[kwarg]在检查所需时为每个提供合理的默认值kwarg

def f(x=0, y=None, z=1):
    if y is None:
        raise Exception()
    return range(x, y, z)
Run Code Online (Sandbox Code Playgroud)

对具有签名的python方法([start],stop,[step])会更有洞察力