我一直在玩 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
现在,错误是显而易见的,并将列表转换为元组将正常工作,就像它在第一时间做的那样:
>>> '1'.startswith(tuple(lis))
True
现在,我的问题是:为什么第一个参数必须是str或str前缀的元组,而不是str前缀列表?
AFAIK, startswith()
的Python代码可能如下所示:
def startswith(src, prefix):
return src[:len(prefix)] == prefix
但这让我更加困惑,因为即使考虑到它,无论是列表还是元组,它仍然不应该有任何区别 . 我错过了什么?
3 回答
技术上没有理由接受其他序列类型,没有 . source code粗略地这样做:
(其中tailmatch(...)执行实际的匹配工作) .
所以是的,任何迭代都可以用于
for
循环 . 但是,所有其他带有多个值的字符串测试API(以及isinstance()
和issubclass()
)也只接受元组,这会告诉您作为API的用户,可以安全地假设该值不会被突变 . 你不能改变元组,但理论上该方法可以改变列表 .另请注意,您通常会测试固定数量的前缀或后缀或类(在
isinstance()
和issubclass()
的情况下);该实现不适合大量元素 . 元组意味着您具有有限数量的元素,而列表可以是任意大的 .接下来,如果任何可迭代或序列类型是可接受的,那么这将包括字符串;单个字符串也是一个序列 . 那么单个字符串参数应该被视为单独的字符,还是单个前缀?
换句话说,自我文档的限制是序列不会被变异,与其他API一致,它带有有限数量的项目的含义来测试,并消除了关于如何单个字符串的歧义论证应该被对待 .
请注意,这是在Python Ideas列表之前提出的;见this thread; Guido van Rossum 's main argument there is that you either special case for single strings or for only accepting a tuple. He picked the latter and doesn' t看到需要改变这一点 .
几年前已经在Python-ideas上提出了这个问题:str.startswith taking any iterator instead of just tuple和GvR有this to say:
除此之外,似乎没有真正的动机为什么这样做 .
当前的方法使事情简单快速,unicode_startswith(和
endswith
)检查元组参数,然后检查字符串1 . 然后他们按适当的方向调用tailmatch . 可以说,这在当前状态下很容易理解,即使对于C代码的陌生人也是如此 .添加其他情况只会导致更加臃肿和复杂的代码,几乎没有什么好处,同时还需要对unicode对象的任何其他部分进行类似的更改 .
在类似的说明中,这里讨论了关于某些字符串方法的API设计选择,包括recent changes to the str.startswith signature . 虽然他简要地提到了这个事实,即
str.startswith
接受了一个字符串或字符串元组并且没有进行阐述,但是关于核心开发人员和贡献者在处理现有API时所做出的决策和痛点,这个话题都是有用的 .