str.startswith如何真正起作用?

时间:2017-07-15 11:57:19

标签: python string list python-3.x tuples

我已经和if (isset($_POST['add20xp'])) { if (!isset($_SESSION['last_post'])) { $_SESSION['last_post'] = 0; } $currtime = time(); if ($currtime > ($_SESSION['last_post'] + 2)) { $_SESSION['last_post'] = $currtime; // ... process the post. $add20xp =("UPDATE users SET exp = (exp + 20)"); // fix this line $execadd20xp = mysqli_query($connection, $add20xp); echo '<meta http-equiv="refresh" content="0.1" />'; } } 玩了一会儿,我发现了一些有趣的东西:

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

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

AFAIK,>>> '1'.startswith(tuple(lis)) True 的Python代码可能如下所示:

startswith()

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

3 个答案:

答案 0 :(得分:26)

技术上没有理由接受其他序列类型,没有。 source code大致这样做:

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(...)

(其中tailmatch(...)执行实际的匹配工作)。

所以是的,任何迭代都可以用于for循环。但是,采用多个值的所有其他字符串测试API(以及isinstance()issubclass())也只接受元组,这告诉您作为API的用户可以安全地假设值不会发生变异。你不能改变一个元组,但理论上该方法可以改变列表。

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

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

所以换句话说,自我文档的限制是序列不会被变异,与其他API一致,它带有有限数量的项目进行测试,并消除了如何模糊应该处理单个字符串参数。

请注意,这是在Python Ideas列表之前提出的;见this thread; Guido van Rossum的主要论点是你要么是单个字符串的特殊情况,要么是只接受一个元组。他选择了后者并且没有必要改变它。

答案 1 :(得分:20)

几年前已经在Python-ideas中提出过这个问题:str.startswith taking any iterator instead of just tuple而GvR有this to say

  

当前行为是故意的,字符串的含糊不清   自己是可迭代的主要原因。由于startswith()是   我知道,无论如何,几乎总是用文字或文字元组调用   几乎没有必要扩展语义。

除此之外,似乎没有真正的动机为何要这样做。

目前的做法让事情变得简单快捷, unicode_startswith(和endswith)检查元组参数,然后检查字符串1。然后他们以适当的方向致电tailmatch。可以说,这在当前状态下很容易理解,即使对于C代码的陌生人也是如此。

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

答案 2 :(得分:2)

在类似的说明中,这里有excerpt from a talk by core developer, Raymond Hettinger讨论关于某些字符串方法的API设计选择,包括recent changes to the str.startswith signature。虽然他简要地提到了str.startswith接受字符串或字符串元组并且没有进行阐述的事实,但是关于核心开发人员和贡献者在处理现有API时所做出的决定和痛点,这个讨论提供了信息。 / p>