str.startswith taking any iterator instead of just tuple
Some functions and methods allow the provision of a tuple of arguments which will be looped over internally. e.g., 'spam'.startswith(('s', 'z')) # 'spam' starts with 's' or with 'z' isinstance(42, (float, int)) In these cases, CPython uses PyTuple_Check and PyTuple_GET_ITEM to perform this internal iteration. As a result, the following are considered invalid: 'spam'.startswith(['s', 'z']) 'spam'.startswith({'s', 'z'}) 'spam'.startswith(x for x in 'sz') Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: startswith first arg must be str, unicode, or tuple There are two common workarounds: 'spam'.startswith(tuple({'s', 'z'})) any('spam'.startwith(c) for c in {'s', 'z'}) Of course, the following construction already has a clear, separate meaning: 'spam'.startswith('sz') # 'spam' starts with 'sz' In these cases, could we supplant the PyTuple_Check with one that would allow any iterator? Alternatively, could add this as an additional branch? The code would look something like: it = PyObject_GetIter(subobj); if (it == NULL) return NULL; iternext = *Py_TYPE(it)->tp_iternext; for(;;) { substring = iternext(it); if (substring == NULL) Py_RETURN_FALSE; result = tailmatch(self, substring, start, end, -1); Py_DECREF(substring); if (result) Py_RETURN_TRUE; } Of course, in the case of methods like .startswith, this would need to ensure the following behaviour remains unchanged. The following should always check if 'spam' starts with 'sz' not starts with 's' or with 'z': 'spam'.startswith('sz') I searched bugs.python.org and python-ideas for any previous discussion of this topic. If this seems reasonable, I can submit an enhancement to bugs.python.org with a patch for unicodeobject.c:unicode_startswith Cheers, James Powell follow: @dontusethiscode + @nycpython attend: nycpython.org + flask-nyc.org read: seriously.dontusethiscode.com
participants (13)
-
Alexander Heger
-
Amber Yust
-
Andrew Barnert
-
Bruce Leban
-
Chris Angelico
-
David Townshend
-
Devin Jeanpierre
-
Eric Snow
-
Guido van Rossum
-
James Powell
-
spir
-
Steven D'Aprano
-
Terry Reedy