str.startswith如何真正起作用?

Caj*_*uu' 18 python string tuples list python-3.x

我一直在玩startswith(),我发现了一些有趣的东西:

>>> tup = ('1', '2', '3')
>>> lis = ['1', '2', '3', '4']
>>> '1'.startswith(tup)
True
>>> '1'.startswith(lis)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: startswith first arg must be str or a tuple of str, not list
Run Code Online (Sandbox Code Playgroud)

现在,错误是显而易见的,并将列表转换为元组将正常工作,就像它在第一时间做的那样:

>>> '1'.startswith(tuple(lis))
True
Run Code Online (Sandbox Code Playgroud)

现在,我的问题是:为什么第一个参数必须是str或str前缀的元组,而不是 str前缀列表

AFAIK,Python代码startswith()可能如下所示:

def startswith(src, prefix):
    return src[:len(prefix)] == prefix
Run Code Online (Sandbox Code Playgroud)

但这让我更加困惑,因为即使考虑到它,无论是列表还是元组,它仍然不应该有任何区别.我错过了什么?

Mar*_*ers 26

技术上没有理由接受其他序列类型,没有.该源代码大致做到这一点:

if isinstance(prefix, tuple):
    for substring in prefix:
        if not isinstance(substring, str):
            raise TypeError(...)
        return tailmatch(...)
elif not isinstance(prefix, str):
    raise TypeError(...)
return tailmatch(...)
Run Code Online (Sandbox Code Playgroud)

(tailmatch(...)实际匹配工作在哪里).

所以是的,任何迭代都可以用于该for循环.但是,所有其他的字符串测试的API(以及isinstance()issubclass()该采取多个值)也只接受元组,这告诉你因为它是安全的假设值的API的用户将不被突变.你不能改变元组,但理论上该方法可以改变列表.

还要注意,通常测试对于固定数量的前缀或后缀或类(在的情况下isinstance()issubclass()); 该实现不适合大量元素.元组意味着您具有有限数量的元素,而列表可以是任意大的.

接下来,如果任何可迭代或序列类型是可接受的,那么这将包括字符串; 单个字符串也是一个序列.那么单个字符串参数应该被视为单独的字符,还是单个前缀?

换句话说,自我文档的限制是序列不会被变异,与其他API一致,它带有有限数量的项目的含义来测试,并消除了关于如何单个字符串的歧义论证应该被对待.

请注意,这是在Python Ideas列表之前提出的; 看到这个帖子 ; Guido van Rossum的主要论点是你要么是单个字符串的特殊情况,要么是只接受一个元组.他选择后者,并没有看到需要改变这一点.

  • 没有投票,但我认为Guido的论点是更有趣的原因.一旦你建立了它就更简单和足以支持一个字符串或一个特定的容器,可变性解释了为什么该容器应该是一个元组而不是一个列表. (7认同)
  • @wim:你是告诉我是我当场编造的原因,还是 Python 开发人员做的?另外,在放弃任何进一步的讨论之前,我将引用 Guido 的观点: [*总而言之,我希望您放弃对此功能的推动。正如我同意的那样,它似乎并不那么重要*](https://mail.python.org/pipermail//python-ideas/2014-January/024664.html)。 (2认同)

Jim*_*ard 20

几年前已经在Python-ideas上提出了这个建议:str.startswith采用任何迭代器而不仅仅是元组和GvR 这样说:

当前行为是有意的,字符串本身是可迭代的模糊性是主要原因.因为startswith()几乎总是用文字或文字元组调用,所以我认为没有必要扩展语义.

除此之外,似乎没有真正的动机为什么这样做.

当前的方法保持简单快速, unicode_startswith(和endswith)检查元组参数,然后检查字符串1.然后他们打电话tailmatch给适当的方向.可以说,这在当前状态下很容易理解,即使对于C代码的陌生人也是如此.

添加其他情况只会导致更加臃肿和复杂的代码,几乎没有什么好处,同时还需要对unicode对象的任何其他部分进行类似的更改.