【问题标题】:Function definition like range函数定义如范围
【发布时间】:2013-06-17 19:41:47
【问题描述】:

假设我想写一个类似range的函数

回想一下,范围有一个参数和 2/3 参数形式:

class range(object)
 |  range(stop) -> range object
 |  range(start, stop[, step]) -> range object

如果我希望方法或函数具有相同的接口,有没有比这更优雅的方法:

def range_like(*args):
    start,stop,step=[None]*3
    if len(args)==1:
        stop=args[0]
    elif len(args)==2:
        start,stop=args
    elif len(args)==3:
        start,stop,step=args
    else:
        raise ValueError       
    print(start,stop,step)

【问题讨论】:

    标签: python function python-3.x


    【解决方案1】:

    这里没有太多建议,但一种替代方法是使用可选参数,如果只提供一个,则交换前两个:

    def range_like(start, stop=None, step=1):
        if stop is None:
            start, stop = 0, start
        ...
    

    【讨论】:

    • 我没有投反对票,但如果None 是一个有效参数,那么您的两个答案都存在问题。考虑接受类似参数的slice()slice(1) 需要等价于slice(None, 1, None),但slice(1, None) 需要等价于slice(1, None, None)
    • 在这种情况下,您可以使用哨兵对象。但是使用 None 作为缺少的参数标记是标准的 Python 实践。
    【解决方案2】:

    我会这样写:

    def range_like(start=None, stop=None, step=1):
        if stop is None:
            start, stop = stop, start
        ...
    

    如果那是你想要的?

    [更新]你也可以添加:

        if stop is start is None:
            raise ValueError()
    

    另外,使用哨兵对象而不是 None (这在 Python 中是不正常的,但你有时会看到):

    NOTSET = object()
    def range_like(start=NOTSET, stop=NOTSET, step=1):
        if stop is NOTSET:
            start, stop = stop, start
    

    允许None 作为参数。

    【讨论】:

    • 为什么这得到了两个反对票?此后,其他人发布了几乎相同的答案。我们都做错了什么?如果您投了反对票,请解释原因。
    • 第一个参数不是可选的应该更明确。如果您改用def range_like(start, stop=None, step=1),则调用range_like() 将产生更有用的错误消息。
    【解决方案3】:

    您不能让可选参数出现在强制参数之前。

    您可以设计变通方法,例如交换参数:

    def range_like(s, t=None, u=None):
        if t is None: 
            s,t = t,s
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-05
      • 2015-03-07
      相关资源
      最近更新 更多