What are the strong use cases for str.rindex()?

Hi all, I found that there are str.index() and str.rindex(), but there is only list.index() and no list.rindex(). So I filed the issue https://bugs.python.org/issue36639 to provide list.rindex(). However, the issue was rejected and closed with the comment: the core APIs unnecessarily. However, I am not sure what the known, strong use cases for str.rindex() are. Why doesn't the strong use cases apply on list.rindex()? Could anyone give me some examples? Thanks. Best, John Lin

Given "abcdefabcdefabcdef", what is the last result of "abc"? x.rindex("abc") will tell you. Given [1, 2, 3, 4, 5, 1, 2, 3, 4, 5] where is the last result of 3? reversed(x).index(3) will tell you (or x[::-1]). Notice how with lists you can easily reverse them and still get at the value since you are searching per index. But with strings, you searching by a subslice that can be greater than 1 in which case you can't use a similar approach. On Mon, Apr 22, 2019 at 11:47 PM 林自均 <johnlinp@gmail.com> wrote:

On Tue, Apr 23, 2019 at 10:28:29AM -0700, Brett Cannon wrote:
That first version doesn't work, as list_reverseiterator objects don't have an index method. You're not the only person to make that error, I too often forget that reverse() returns an iterator, not a list. The second is easy to get wrong, because it returns the wrong index: # Get the item following the last instance of spam. index = x[::-1].index(spam) print(x[index+1]) In your example, the correct index is 7 but the returned value is 2.
Notice how with lists you can easily reverse them and still get at the value since you are searching per index.
"Easily" hides a lot of copying behind the scenes. If the list is a non-trivial size, that can be very wasteful, especially if you're doing it in a loop, or hidden in a function. Don't think about the case of a ten element list, think of a ten-billion element list. Personally, I don't think I've every used list.index, let alone needed rindex. But I think we underestimate the difficulty and cost of faking an rindex method from index for those who need it (if anyone does).
Of course you can: you "just" need to reverse the substring as well. The conversions will be even more fiddly and error-prone: py> s = "abc spam def spam ghi" py> s.rindex('spam') == len(s) - s[::-1].index('spam'[::-1]) - len('spam') True but it can be done. -- Steven

On 4/25/2019 7:12 PM, Greg Ewing wrote:
Steven D'Aprano wrote:
I too often forget that reverse() returns an iterator,
I presume you mean reversed(). list.reverse() is a list
That seems like a mistake. Shouldn't it return a view?
RL = reversed(somelist) is already partly view-like. The nth next call returns the nth item at the time of the next call, rather than at the time of the reversed call. However, the number of items produced by next calls is the length of the list at the time of the reversed call. The first next(RL) is the current somelist[captured_length].
-- Terry Jan Reedy

On Fri, Apr 26, 2019 at 12:17:57AM -0400, Terry Reedy wrote:
Yes, I meant reversed(), not list.reverse() which is an in-place mutator method and returns None.
That's not quite correct: py> L = [1, 2, 3] py> R = reversed(L) py> L.clear() py> next(R) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration It seems that: - in-place modifications in the list are reflected in the items yielded (so reversed() doesn't make a copy of the list); - operations which extend the length of the list don't show up in the reversed version; - and operations which decrease the length of the list decrease the number of items yielded. That suggests to me an implementation similar to: # untested def reversed(alist): N = len(alist) for i in range(N-1, -1, -1): try: yield alist[i] except IndexError: break raise StopIteration which I suppose is close to what you meant here:
The first next(RL) is the current somelist[captured_length].
-- Steven

On 4/23/2019 2:44 AM, 林自均 wrote:
str.index and list.index are related but not the same. The consistency argument is better applied to find-rfind, index-rindex, partition-rpartition, etc. It is much more common to process strings right to left or in both directions, than process lists right to left or in both directions. Moreover, lists have a reverse method, strings do not. ''.join(reversed(somestring)) is likely slower, especially if there many non-ascii chars. Moreover, somestring.rindex(substring) would have to have both somestring and substring reversed when substring is more than one char. So I filed the issue
Omitting tests of rindex and rfind themselves: Searching 'rindex' in C:\Programs\Python38\lib\*.py ... C:\Programs\Python38\lib\_markupbase.py: 55: pos = rawdata.rindex("\n", i, j) # Should not fail C:\Programs\Python38\lib\collections\__init__.py: 1260: def rindex(self, sub, start=0, end=_sys.maxsize): C:\Programs\Python38\lib\collections\__init__.py: 1261: return self.data.rindex(sub, start, end) C:\Programs\Python38\lib\pydoc_data\topics.py: 10125: 'str.rindex(sub[, start[, end]])\n' C:\Programs\Python38\lib\test\pickletester.py: 2543: self.assertEqual((pickled.rindex(b"abcd") + len(b"abcd") - C:\Programs\Python38\lib\test\pickletester.py: 2574: self.assertEqual((pickled.rindex(b"abcd") + len(b"abcd") - C:\Programs\Python38\lib\test\test_baseexception.py: 46: depth = exc_line.rindex('-') C:\Programs\Python38\lib\test\test_bigmem.py: 310: self.assertEqual(s.rindex(_(' ')), C:\Programs\Python38\lib\test\test_bigmem.py: 311: sublen + size + SUBSTR.rindex(_(' '))) C:\Programs\Python38\lib\test\test_bigmem.py: 312: self.assertEqual(s.rindex(SUBSTR), sublen + size) C:\Programs\Python38\lib\test\test_bigmem.py: 313: self.assertEqual(s.rindex(_(' '), 0, sublen + size - 1), C:\Programs\Python38\lib\test\test_bigmem.py: 314: SUBSTR.rindex(_(' '))) C:\Programs\Python38\lib\test\test_bigmem.py: 315: self.assertEqual(s.rindex(SUBSTR, 0, sublen + size), 0) C:\Programs\Python38\lib\test\test_bigmem.py: 316: self.assertEqual(s.rindex(_('i')), C:\Programs\Python38\lib\test\test_bigmem.py: 317: sublen + size + SUBSTR.rindex(_('i'))) C:\Programs\Python38\lib\test\test_bigmem.py: 318: self.assertEqual(s.rindex(_('i'), 0, sublen), SUBSTR.rindex(_('i'))) C:\Programs\Python38\lib\test\test_bigmem.py: 319: self.assertEqual(s.rindex(_('i'), 0, sublen + size), C:\Programs\Python38\lib\test\test_bigmem.py: 320: SUBSTR.rindex(_('i'))) C:\Programs\Python38\lib\test\test_bigmem.py: 321: self.assertRaises(ValueError, s.rindex, _('j')) C:\Programs\Python38\lib\test\test_bytes.py: 566: self.assertEqual(b.rindex(b'ss'), 5) C:\Programs\Python38\lib\test\test_bytes.py: 567: self.assertRaises(ValueError, b.rindex, b'w') C:\Programs\Python38\lib\test\test_bytes.py: 568: self.assertRaises(ValueError, b.rindex, b'mississippian') C:\Programs\Python38\lib\test\test_bytes.py: 570: self.assertEqual(b.rindex(i), 10) C:\Programs\Python38\lib\test\test_bytes.py: 571: self.assertRaises(ValueError, b.rindex, w) C:\Programs\Python38\lib\test\test_bytes.py: 573: self.assertEqual(b.rindex(b'ss', 3), 5) C:\Programs\Python38\lib\test\test_bytes.py: 574: self.assertEqual(b.rindex(b'ss', 0, 6), 2) C:\Programs\Python38\lib\test\test_bytes.py: 576: self.assertEqual(b.rindex(i, 1, 3), 1) C:\Programs\Python38\lib\test\test_bytes.py: 577: self.assertEqual(b.rindex(i, 3, 9), 7) C:\Programs\Python38\lib\test\test_bytes.py: 578: self.assertRaises(ValueError, b.rindex, w, 1, 3) C:\Programs\Python38\lib\test\test_bytes.py: 768: self.assertEqual(3, b.rindex(l, None)) C:\Programs\Python38\lib\test\test_bytes.py: 769: self.assertEqual(3, b.rindex(l, -2, None)) C:\Programs\Python38\lib\test\test_bytes.py: 770: self.assertEqual(2, b.rindex(l, None, -2)) C:\Programs\Python38\lib\test\test_bytes.py: 771: self.assertEqual(0, b.rindex(h, None, None)) C:\Programs\Python38\lib\test\test_bytes.py: 791: for method in (b.count, b.find, b.index, b.rfind, b.rindex): C:\Programs\Python38\lib\test\test_bytes.py: 806: self.assertRaisesRegex(TypeError, r'\brindex\b', b.rindex, C:\Programs\Python38\lib\test\test_descr.py: 3596: try: ''.rindex('5') C:\Programs\Python38\lib\test\test_descr.py: 3598: else: self.fail("''.rindex('5') doesn't raise ValueError") Searching 'rfind' in C:\Programs\Python38\lib\*.py ... C:\Programs\Python38\lib\collections\__init__.py: 1256: def rfind(self, sub, start=0, end=_sys.maxsize): C:\Programs\Python38\lib\collections\__init__.py: 1259: return self.data.rfind(sub, start, end) C:\Programs\Python38\lib\ctypes\macholib\dyld.py: 143: fmwk_index = fn.rfind('.framework') C:\Programs\Python38\lib\doctest.py: 341: i = msg.rfind('.', 0, end) C:\Programs\Python38\lib\email\_parseaddr.py: 76: i = data[0].rfind(',') C:\Programs\Python38\lib\encodings\punycode.py: 187: pos = text.rfind(b"-") C:\Programs\Python38\lib\formatter.py: 401: i = data.rfind('\n') C:\Programs\Python38\lib\genericpath.py: 124: sepIndex = p.rfind(sep) C:\Programs\Python38\lib\genericpath.py: 126: altsepIndex = p.rfind(altsep) C:\Programs\Python38\lib\genericpath.py: 129: dotIndex = p.rfind(extsep) C:\Programs\Python38\lib\html\parser.py: 148: amppos = rawdata.rfind('&', max(i, n-34)) C:\Programs\Python38\lib\html\parser.py: 336: - self.__starttag_text.rfind("\n") C:\Programs\Python38\lib\http\client.py: 873: i = host.rfind(':') C:\Programs\Python38\lib\http\client.py: 874: j = host.rfind(']') # ipv6 addresses have [...] C:\Programs\Python38\lib\http\cookiejar.py: 566: i = A.rfind(B) C:\Programs\Python38\lib\http\cookiejar.py: 1016: i = domain.rfind(".") C:\Programs\Python38\lib\http\cookiejar.py: 1017: j = domain.rfind(".", 0, i) C:\Programs\Python38\lib\http\cookiejar.py: 1507: i = path.rfind("/") C:\Programs\Python38\lib\idlelib\pyparse.py: 161: i = code.rfind(":\n", 0, limit) C:\Programs\Python38\lib\idlelib\pyparse.py: 164: i = code.rfind('\n', 0, i) + 1 # start of colon line (-1+1=0) C:\Programs\Python38\lib\idlelib\pyparse.py: 379: p = code.rfind('\n', 0, p-1) + 1 C:\Programs\Python38\lib\idlelib\pyparse.py: 477: origi = i = code.rfind('\n', 0, j) + 1 C:\Programs\Python38\lib\json\decoder.py: 33: colno = pos - doc.rfind('\n', 0, pos) C:\Programs\Python38\lib\logging\__init__.py: 1340: i = name.rfind(".") C:\Programs\Python38\lib\logging\__init__.py: 1353: i = name.rfind(".", 0, i - 1) C:\Programs\Python38\lib\modulefinder.py: 155: i = pname.rfind('.') C:\Programs\Python38\lib\modulefinder.py: 509: i = name.rfind(".") C:\Programs\Python38\lib\pathlib.py: 791: i = name.rfind('.') C:\Programs\Python38\lib\pathlib.py: 810: i = name.rfind('.') C:\Programs\Python38\lib\pdb.py: 629: colon = arg.rfind(':') C:\Programs\Python38\lib\pdb.py: 884: i = arg.rfind(':') C:\Programs\Python38\lib\posixpath.py: 109: i = p.rfind(sep) + 1 C:\Programs\Python38\lib\posixpath.py: 148: i = p.rfind(sep) + 1 C:\Programs\Python38\lib\posixpath.py: 158: i = p.rfind(sep) + 1 C:\Programs\Python38\lib\pyclbr.py: 145: i = module.rfind('.') C:\Programs\Python38\lib\pydoc.py: 1657: desc += ' in ' + name[:name.rfind('.')] C:\Programs\Python38\lib\pydoc_data\topics.py: 10115: 'str.rfind(sub[, start[, end]])\n' C:\Programs\Python38\lib\pydoc_data\topics.py: 10127: ' Like "rfind()" but raises "ValueError" when the ' C:\Programs\Python38\lib\site-packages\pip\_vendor\html5lib\_inputstream.py: 228: lastLinePos = chunk.rfind('\n', 0, offset) C:\Programs\Python38\lib\site-packages\pip\_vendor\pyparsing.py: 1110: return 1 if 0<loc<len(s) and s[loc-1] == '\n' else loc - s.rfind("\n", 0, loc) C:\Programs\Python38\lib\site-packages\pip\_vendor\pyparsing.py: 1127: lastCR = strg.rfind("\n", 0, loc) C:\Programs\Python38\lib\site-packages\pip\_vendor\pytoml\parser.py: 169: suffix_pos = s.rfind('\n') C:\Programs\Python38\lib\site-packages\pkg_resources\_vendor\pyparsing.py: 979: return 1 if 0<loc<len(s) and s[loc-1] == '\n' else loc - s.rfind("\n", 0, loc) C:\Programs\Python38\lib\site-packages\pkg_resources\_vendor\pyparsing.py: 996: lastCR = strg.rfind("\n", 0, loc) C:\Programs\Python38\lib\site-packages\setuptools\_vendor\pyparsing.py: 979: return 1 if 0<loc<len(s) and s[loc-1] == '\n' else loc - s.rfind("\n", 0, loc) C:\Programs\Python38\lib\site-packages\setuptools\_vendor\pyparsing.py: 996: lastCR = strg.rfind("\n", 0, loc) C:\Programs\Python38\lib\site-packages\setuptools\msvc.py: 627: intver = ver[:ver.rfind('.')] C:\Programs\Python38\lib\smtpd.py: 941: lastdot = classname.rfind(".") C:\Programs\Python38\lib\smtplib.py: 326: if not port and (host.find(':') == host.rfind(':')): C:\Programs\Python38\lib\smtplib.py: 327: i = host.rfind(':') C:\Programs\Python38\lib\sre_constants.py: 48: self.colno = pos - pattern.rfind(newline, 0, pos) C:\Programs\Python38\lib\test\test_bigmem.py: 294: self.assertEqual(s.rfind(_(' ')), sublen + size + SUBSTR.rfind(_(' '))) C:\Programs\Python38\lib\test\test_bigmem.py: 295: self.assertEqual(s.rfind(SUBSTR), sublen + size) C:\Programs\Python38\lib\test\test_bigmem.py: 296: self.assertEqual(s.rfind(_(' '), 0, size), SUBSTR.rfind(_(' '))) C:\Programs\Python38\lib\test\test_bigmem.py: 297: self.assertEqual(s.rfind(SUBSTR, 0, sublen + size), 0) C:\Programs\Python38\lib\test\test_bigmem.py: 298: self.assertEqual(s.rfind(_('i')), sublen + size + SUBSTR.rfind(_('i'))) C:\Programs\Python38\lib\test\test_bigmem.py: 299: self.assertEqual(s.rfind(_('i'), 0, sublen), SUBSTR.rfind(_('i'))) C:\Programs\Python38\lib\test\test_bigmem.py: 300: self.assertEqual(s.rfind(_('i'), 0, sublen + size), C:\Programs\Python38\lib\test\test_bigmem.py: 301: SUBSTR.rfind(_('i'))) C:\Programs\Python38\lib\test\test_bigmem.py: 302: self.assertEqual(s.rfind(_('j')), -1) C:\Programs\Python38\lib\test\test_bytes.py: 527: self.assertEqual(b.rfind(b'ss'), 5) C:\Programs\Python38\lib\test\test_bytes.py: 528: self.assertEqual(b.rfind(b'w'), -1) C:\Programs\Python38\lib\test\test_bytes.py: 529: self.assertEqual(b.rfind(b'mississippian'), -1) C:\Programs\Python38\lib\test\test_bytes.py: 531: self.assertEqual(b.rfind(i), 10) C:\Programs\Python38\lib\test\test_bytes.py: 532: self.assertEqual(b.rfind(w), -1) C:\Programs\Python38\lib\test\test_bytes.py: 534: self.assertEqual(b.rfind(b'ss', 3), 5) C:\Programs\Python38\lib\test\test_bytes.py: 535: self.assertEqual(b.rfind(b'ss', 0, 6), 2) C:\Programs\Python38\lib\test\test_bytes.py: 537: self.assertEqual(b.rfind(i, 1, 3), 1) C:\Programs\Python38\lib\test\test_bytes.py: 538: self.assertEqual(b.rfind(i, 3, 9), 7) C:\Programs\Python38\lib\test\test_bytes.py: 539: self.assertEqual(b.rfind(w, 1, 3), -1) C:\Programs\Python38\lib\test\test_bytes.py: 758: self.assertEqual(3, b.rfind(l, None)) C:\Programs\Python38\lib\test\test_bytes.py: 759: self.assertEqual(3, b.rfind(l, -2, None)) C:\Programs\Python38\lib\test\test_bytes.py: 760: self.assertEqual(2, b.rfind(l, None, -2)) C:\Programs\Python38\lib\test\test_bytes.py: 761: self.assertEqual(0, b.rfind(h, None, None)) C:\Programs\Python38\lib\test\test_bytes.py: 791: for method in (b.count, b.find, b.index, b.rfind, b.rindex): C:\Programs\Python38\lib\test\test_bytes.py: 802: self.assertRaisesRegex(TypeError, r'\brfind\b', b.rfind, C:\Programs\Python38\lib\test\test_mmap.py: 296: self.assertEqual(m.rfind(b'one'), 8) C:\Programs\Python38\lib\test\test_mmap.py: 297: self.assertEqual(m.rfind(b'one '), 0) C:\Programs\Python38\lib\test\test_mmap.py: 298: self.assertEqual(m.rfind(b'one', 0, -1), 8) C:\Programs\Python38\lib\test\test_mmap.py: 299: self.assertEqual(m.rfind(b'one', 0, -2), 0) C:\Programs\Python38\lib\test\test_mmap.py: 300: self.assertEqual(m.rfind(b'one', 1, -1), 8) C:\Programs\Python38\lib\test\test_mmap.py: 301: self.assertEqual(m.rfind(b'one', 1, -2), -1) C:\Programs\Python38\lib\test\test_mmap.py: 302: self.assertEqual(m.rfind(bytearray(b'one')), 8) C:\Programs\Python38\lib\test\test_socket.py: 313: i = methodname.rfind('.') C:\Programs\Python38\lib\test\test_urllib2.py: 398: code = action[action.rfind(" ")+1:] C:\Programs\Python38\lib\urllib\parse.py: 384: i = url.find(';', url.rfind('/')) C:\Programs\Python38\lib\urllib\request.py: 2083: semi = type.rfind(';') C:\Programs\Python38\lib\warnings.py: 260: i = category.rfind(".") C:\Programs\Python38\lib\zipfile.py: 292: start = data.rfind(stringEndArchive) C:\Programs\Python38\lib\zipimport.py: 384: pos = data.rfind(STRING_END_ARCHIVE) Hits found: 136 (Hint: right-click to open locations.) -- Terry Jan Reedy

On Tue, Apr 23, 2019 at 1:02 PM MRAB <python@mrabarnett.plus.com> wrote:
Me neither, though for substring checks, reversing the string would be even more cumbersome (you'd have to reverse the query string too). My money is on "nobody uses this for lists". Some use cases for rindex() on strings that I found in a large codebase here include searching a pathname for the final slash, a list of comma-separated items for the last comma, a fully-qualified module name for the last period, and some ad-hoc parsing of other things. The "last separator" use cases are the most common and here rindex() sounds very useful. -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him/his **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>

Hi all, Thanks for the explanation. Now I agree that the need for list.rindex() is not as common as str.rindex(). In fact, I only need list.rindex() when doing some algorithm problems. I guess that doesn't count as real need here. Best, John Lin Guido van Rossum <guido@python.org> 於 2019年4月24日 週三 上午4:20寫道:

Given "abcdefabcdefabcdef", what is the last result of "abc"? x.rindex("abc") will tell you. Given [1, 2, 3, 4, 5, 1, 2, 3, 4, 5] where is the last result of 3? reversed(x).index(3) will tell you (or x[::-1]). Notice how with lists you can easily reverse them and still get at the value since you are searching per index. But with strings, you searching by a subslice that can be greater than 1 in which case you can't use a similar approach. On Mon, Apr 22, 2019 at 11:47 PM 林自均 <johnlinp@gmail.com> wrote:

On Tue, Apr 23, 2019 at 10:28:29AM -0700, Brett Cannon wrote:
That first version doesn't work, as list_reverseiterator objects don't have an index method. You're not the only person to make that error, I too often forget that reverse() returns an iterator, not a list. The second is easy to get wrong, because it returns the wrong index: # Get the item following the last instance of spam. index = x[::-1].index(spam) print(x[index+1]) In your example, the correct index is 7 but the returned value is 2.
Notice how with lists you can easily reverse them and still get at the value since you are searching per index.
"Easily" hides a lot of copying behind the scenes. If the list is a non-trivial size, that can be very wasteful, especially if you're doing it in a loop, or hidden in a function. Don't think about the case of a ten element list, think of a ten-billion element list. Personally, I don't think I've every used list.index, let alone needed rindex. But I think we underestimate the difficulty and cost of faking an rindex method from index for those who need it (if anyone does).
Of course you can: you "just" need to reverse the substring as well. The conversions will be even more fiddly and error-prone: py> s = "abc spam def spam ghi" py> s.rindex('spam') == len(s) - s[::-1].index('spam'[::-1]) - len('spam') True but it can be done. -- Steven

On 4/25/2019 7:12 PM, Greg Ewing wrote:
Steven D'Aprano wrote:
I too often forget that reverse() returns an iterator,
I presume you mean reversed(). list.reverse() is a list
That seems like a mistake. Shouldn't it return a view?
RL = reversed(somelist) is already partly view-like. The nth next call returns the nth item at the time of the next call, rather than at the time of the reversed call. However, the number of items produced by next calls is the length of the list at the time of the reversed call. The first next(RL) is the current somelist[captured_length].
-- Terry Jan Reedy

On Fri, Apr 26, 2019 at 12:17:57AM -0400, Terry Reedy wrote:
Yes, I meant reversed(), not list.reverse() which is an in-place mutator method and returns None.
That's not quite correct: py> L = [1, 2, 3] py> R = reversed(L) py> L.clear() py> next(R) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration It seems that: - in-place modifications in the list are reflected in the items yielded (so reversed() doesn't make a copy of the list); - operations which extend the length of the list don't show up in the reversed version; - and operations which decrease the length of the list decrease the number of items yielded. That suggests to me an implementation similar to: # untested def reversed(alist): N = len(alist) for i in range(N-1, -1, -1): try: yield alist[i] except IndexError: break raise StopIteration which I suppose is close to what you meant here:
The first next(RL) is the current somelist[captured_length].
-- Steven

On 4/23/2019 2:44 AM, 林自均 wrote:
str.index and list.index are related but not the same. The consistency argument is better applied to find-rfind, index-rindex, partition-rpartition, etc. It is much more common to process strings right to left or in both directions, than process lists right to left or in both directions. Moreover, lists have a reverse method, strings do not. ''.join(reversed(somestring)) is likely slower, especially if there many non-ascii chars. Moreover, somestring.rindex(substring) would have to have both somestring and substring reversed when substring is more than one char. So I filed the issue
Omitting tests of rindex and rfind themselves: Searching 'rindex' in C:\Programs\Python38\lib\*.py ... C:\Programs\Python38\lib\_markupbase.py: 55: pos = rawdata.rindex("\n", i, j) # Should not fail C:\Programs\Python38\lib\collections\__init__.py: 1260: def rindex(self, sub, start=0, end=_sys.maxsize): C:\Programs\Python38\lib\collections\__init__.py: 1261: return self.data.rindex(sub, start, end) C:\Programs\Python38\lib\pydoc_data\topics.py: 10125: 'str.rindex(sub[, start[, end]])\n' C:\Programs\Python38\lib\test\pickletester.py: 2543: self.assertEqual((pickled.rindex(b"abcd") + len(b"abcd") - C:\Programs\Python38\lib\test\pickletester.py: 2574: self.assertEqual((pickled.rindex(b"abcd") + len(b"abcd") - C:\Programs\Python38\lib\test\test_baseexception.py: 46: depth = exc_line.rindex('-') C:\Programs\Python38\lib\test\test_bigmem.py: 310: self.assertEqual(s.rindex(_(' ')), C:\Programs\Python38\lib\test\test_bigmem.py: 311: sublen + size + SUBSTR.rindex(_(' '))) C:\Programs\Python38\lib\test\test_bigmem.py: 312: self.assertEqual(s.rindex(SUBSTR), sublen + size) C:\Programs\Python38\lib\test\test_bigmem.py: 313: self.assertEqual(s.rindex(_(' '), 0, sublen + size - 1), C:\Programs\Python38\lib\test\test_bigmem.py: 314: SUBSTR.rindex(_(' '))) C:\Programs\Python38\lib\test\test_bigmem.py: 315: self.assertEqual(s.rindex(SUBSTR, 0, sublen + size), 0) C:\Programs\Python38\lib\test\test_bigmem.py: 316: self.assertEqual(s.rindex(_('i')), C:\Programs\Python38\lib\test\test_bigmem.py: 317: sublen + size + SUBSTR.rindex(_('i'))) C:\Programs\Python38\lib\test\test_bigmem.py: 318: self.assertEqual(s.rindex(_('i'), 0, sublen), SUBSTR.rindex(_('i'))) C:\Programs\Python38\lib\test\test_bigmem.py: 319: self.assertEqual(s.rindex(_('i'), 0, sublen + size), C:\Programs\Python38\lib\test\test_bigmem.py: 320: SUBSTR.rindex(_('i'))) C:\Programs\Python38\lib\test\test_bigmem.py: 321: self.assertRaises(ValueError, s.rindex, _('j')) C:\Programs\Python38\lib\test\test_bytes.py: 566: self.assertEqual(b.rindex(b'ss'), 5) C:\Programs\Python38\lib\test\test_bytes.py: 567: self.assertRaises(ValueError, b.rindex, b'w') C:\Programs\Python38\lib\test\test_bytes.py: 568: self.assertRaises(ValueError, b.rindex, b'mississippian') C:\Programs\Python38\lib\test\test_bytes.py: 570: self.assertEqual(b.rindex(i), 10) C:\Programs\Python38\lib\test\test_bytes.py: 571: self.assertRaises(ValueError, b.rindex, w) C:\Programs\Python38\lib\test\test_bytes.py: 573: self.assertEqual(b.rindex(b'ss', 3), 5) C:\Programs\Python38\lib\test\test_bytes.py: 574: self.assertEqual(b.rindex(b'ss', 0, 6), 2) C:\Programs\Python38\lib\test\test_bytes.py: 576: self.assertEqual(b.rindex(i, 1, 3), 1) C:\Programs\Python38\lib\test\test_bytes.py: 577: self.assertEqual(b.rindex(i, 3, 9), 7) C:\Programs\Python38\lib\test\test_bytes.py: 578: self.assertRaises(ValueError, b.rindex, w, 1, 3) C:\Programs\Python38\lib\test\test_bytes.py: 768: self.assertEqual(3, b.rindex(l, None)) C:\Programs\Python38\lib\test\test_bytes.py: 769: self.assertEqual(3, b.rindex(l, -2, None)) C:\Programs\Python38\lib\test\test_bytes.py: 770: self.assertEqual(2, b.rindex(l, None, -2)) C:\Programs\Python38\lib\test\test_bytes.py: 771: self.assertEqual(0, b.rindex(h, None, None)) C:\Programs\Python38\lib\test\test_bytes.py: 791: for method in (b.count, b.find, b.index, b.rfind, b.rindex): C:\Programs\Python38\lib\test\test_bytes.py: 806: self.assertRaisesRegex(TypeError, r'\brindex\b', b.rindex, C:\Programs\Python38\lib\test\test_descr.py: 3596: try: ''.rindex('5') C:\Programs\Python38\lib\test\test_descr.py: 3598: else: self.fail("''.rindex('5') doesn't raise ValueError") Searching 'rfind' in C:\Programs\Python38\lib\*.py ... C:\Programs\Python38\lib\collections\__init__.py: 1256: def rfind(self, sub, start=0, end=_sys.maxsize): C:\Programs\Python38\lib\collections\__init__.py: 1259: return self.data.rfind(sub, start, end) C:\Programs\Python38\lib\ctypes\macholib\dyld.py: 143: fmwk_index = fn.rfind('.framework') C:\Programs\Python38\lib\doctest.py: 341: i = msg.rfind('.', 0, end) C:\Programs\Python38\lib\email\_parseaddr.py: 76: i = data[0].rfind(',') C:\Programs\Python38\lib\encodings\punycode.py: 187: pos = text.rfind(b"-") C:\Programs\Python38\lib\formatter.py: 401: i = data.rfind('\n') C:\Programs\Python38\lib\genericpath.py: 124: sepIndex = p.rfind(sep) C:\Programs\Python38\lib\genericpath.py: 126: altsepIndex = p.rfind(altsep) C:\Programs\Python38\lib\genericpath.py: 129: dotIndex = p.rfind(extsep) C:\Programs\Python38\lib\html\parser.py: 148: amppos = rawdata.rfind('&', max(i, n-34)) C:\Programs\Python38\lib\html\parser.py: 336: - self.__starttag_text.rfind("\n") C:\Programs\Python38\lib\http\client.py: 873: i = host.rfind(':') C:\Programs\Python38\lib\http\client.py: 874: j = host.rfind(']') # ipv6 addresses have [...] C:\Programs\Python38\lib\http\cookiejar.py: 566: i = A.rfind(B) C:\Programs\Python38\lib\http\cookiejar.py: 1016: i = domain.rfind(".") C:\Programs\Python38\lib\http\cookiejar.py: 1017: j = domain.rfind(".", 0, i) C:\Programs\Python38\lib\http\cookiejar.py: 1507: i = path.rfind("/") C:\Programs\Python38\lib\idlelib\pyparse.py: 161: i = code.rfind(":\n", 0, limit) C:\Programs\Python38\lib\idlelib\pyparse.py: 164: i = code.rfind('\n', 0, i) + 1 # start of colon line (-1+1=0) C:\Programs\Python38\lib\idlelib\pyparse.py: 379: p = code.rfind('\n', 0, p-1) + 1 C:\Programs\Python38\lib\idlelib\pyparse.py: 477: origi = i = code.rfind('\n', 0, j) + 1 C:\Programs\Python38\lib\json\decoder.py: 33: colno = pos - doc.rfind('\n', 0, pos) C:\Programs\Python38\lib\logging\__init__.py: 1340: i = name.rfind(".") C:\Programs\Python38\lib\logging\__init__.py: 1353: i = name.rfind(".", 0, i - 1) C:\Programs\Python38\lib\modulefinder.py: 155: i = pname.rfind('.') C:\Programs\Python38\lib\modulefinder.py: 509: i = name.rfind(".") C:\Programs\Python38\lib\pathlib.py: 791: i = name.rfind('.') C:\Programs\Python38\lib\pathlib.py: 810: i = name.rfind('.') C:\Programs\Python38\lib\pdb.py: 629: colon = arg.rfind(':') C:\Programs\Python38\lib\pdb.py: 884: i = arg.rfind(':') C:\Programs\Python38\lib\posixpath.py: 109: i = p.rfind(sep) + 1 C:\Programs\Python38\lib\posixpath.py: 148: i = p.rfind(sep) + 1 C:\Programs\Python38\lib\posixpath.py: 158: i = p.rfind(sep) + 1 C:\Programs\Python38\lib\pyclbr.py: 145: i = module.rfind('.') C:\Programs\Python38\lib\pydoc.py: 1657: desc += ' in ' + name[:name.rfind('.')] C:\Programs\Python38\lib\pydoc_data\topics.py: 10115: 'str.rfind(sub[, start[, end]])\n' C:\Programs\Python38\lib\pydoc_data\topics.py: 10127: ' Like "rfind()" but raises "ValueError" when the ' C:\Programs\Python38\lib\site-packages\pip\_vendor\html5lib\_inputstream.py: 228: lastLinePos = chunk.rfind('\n', 0, offset) C:\Programs\Python38\lib\site-packages\pip\_vendor\pyparsing.py: 1110: return 1 if 0<loc<len(s) and s[loc-1] == '\n' else loc - s.rfind("\n", 0, loc) C:\Programs\Python38\lib\site-packages\pip\_vendor\pyparsing.py: 1127: lastCR = strg.rfind("\n", 0, loc) C:\Programs\Python38\lib\site-packages\pip\_vendor\pytoml\parser.py: 169: suffix_pos = s.rfind('\n') C:\Programs\Python38\lib\site-packages\pkg_resources\_vendor\pyparsing.py: 979: return 1 if 0<loc<len(s) and s[loc-1] == '\n' else loc - s.rfind("\n", 0, loc) C:\Programs\Python38\lib\site-packages\pkg_resources\_vendor\pyparsing.py: 996: lastCR = strg.rfind("\n", 0, loc) C:\Programs\Python38\lib\site-packages\setuptools\_vendor\pyparsing.py: 979: return 1 if 0<loc<len(s) and s[loc-1] == '\n' else loc - s.rfind("\n", 0, loc) C:\Programs\Python38\lib\site-packages\setuptools\_vendor\pyparsing.py: 996: lastCR = strg.rfind("\n", 0, loc) C:\Programs\Python38\lib\site-packages\setuptools\msvc.py: 627: intver = ver[:ver.rfind('.')] C:\Programs\Python38\lib\smtpd.py: 941: lastdot = classname.rfind(".") C:\Programs\Python38\lib\smtplib.py: 326: if not port and (host.find(':') == host.rfind(':')): C:\Programs\Python38\lib\smtplib.py: 327: i = host.rfind(':') C:\Programs\Python38\lib\sre_constants.py: 48: self.colno = pos - pattern.rfind(newline, 0, pos) C:\Programs\Python38\lib\test\test_bigmem.py: 294: self.assertEqual(s.rfind(_(' ')), sublen + size + SUBSTR.rfind(_(' '))) C:\Programs\Python38\lib\test\test_bigmem.py: 295: self.assertEqual(s.rfind(SUBSTR), sublen + size) C:\Programs\Python38\lib\test\test_bigmem.py: 296: self.assertEqual(s.rfind(_(' '), 0, size), SUBSTR.rfind(_(' '))) C:\Programs\Python38\lib\test\test_bigmem.py: 297: self.assertEqual(s.rfind(SUBSTR, 0, sublen + size), 0) C:\Programs\Python38\lib\test\test_bigmem.py: 298: self.assertEqual(s.rfind(_('i')), sublen + size + SUBSTR.rfind(_('i'))) C:\Programs\Python38\lib\test\test_bigmem.py: 299: self.assertEqual(s.rfind(_('i'), 0, sublen), SUBSTR.rfind(_('i'))) C:\Programs\Python38\lib\test\test_bigmem.py: 300: self.assertEqual(s.rfind(_('i'), 0, sublen + size), C:\Programs\Python38\lib\test\test_bigmem.py: 301: SUBSTR.rfind(_('i'))) C:\Programs\Python38\lib\test\test_bigmem.py: 302: self.assertEqual(s.rfind(_('j')), -1) C:\Programs\Python38\lib\test\test_bytes.py: 527: self.assertEqual(b.rfind(b'ss'), 5) C:\Programs\Python38\lib\test\test_bytes.py: 528: self.assertEqual(b.rfind(b'w'), -1) C:\Programs\Python38\lib\test\test_bytes.py: 529: self.assertEqual(b.rfind(b'mississippian'), -1) C:\Programs\Python38\lib\test\test_bytes.py: 531: self.assertEqual(b.rfind(i), 10) C:\Programs\Python38\lib\test\test_bytes.py: 532: self.assertEqual(b.rfind(w), -1) C:\Programs\Python38\lib\test\test_bytes.py: 534: self.assertEqual(b.rfind(b'ss', 3), 5) C:\Programs\Python38\lib\test\test_bytes.py: 535: self.assertEqual(b.rfind(b'ss', 0, 6), 2) C:\Programs\Python38\lib\test\test_bytes.py: 537: self.assertEqual(b.rfind(i, 1, 3), 1) C:\Programs\Python38\lib\test\test_bytes.py: 538: self.assertEqual(b.rfind(i, 3, 9), 7) C:\Programs\Python38\lib\test\test_bytes.py: 539: self.assertEqual(b.rfind(w, 1, 3), -1) C:\Programs\Python38\lib\test\test_bytes.py: 758: self.assertEqual(3, b.rfind(l, None)) C:\Programs\Python38\lib\test\test_bytes.py: 759: self.assertEqual(3, b.rfind(l, -2, None)) C:\Programs\Python38\lib\test\test_bytes.py: 760: self.assertEqual(2, b.rfind(l, None, -2)) C:\Programs\Python38\lib\test\test_bytes.py: 761: self.assertEqual(0, b.rfind(h, None, None)) C:\Programs\Python38\lib\test\test_bytes.py: 791: for method in (b.count, b.find, b.index, b.rfind, b.rindex): C:\Programs\Python38\lib\test\test_bytes.py: 802: self.assertRaisesRegex(TypeError, r'\brfind\b', b.rfind, C:\Programs\Python38\lib\test\test_mmap.py: 296: self.assertEqual(m.rfind(b'one'), 8) C:\Programs\Python38\lib\test\test_mmap.py: 297: self.assertEqual(m.rfind(b'one '), 0) C:\Programs\Python38\lib\test\test_mmap.py: 298: self.assertEqual(m.rfind(b'one', 0, -1), 8) C:\Programs\Python38\lib\test\test_mmap.py: 299: self.assertEqual(m.rfind(b'one', 0, -2), 0) C:\Programs\Python38\lib\test\test_mmap.py: 300: self.assertEqual(m.rfind(b'one', 1, -1), 8) C:\Programs\Python38\lib\test\test_mmap.py: 301: self.assertEqual(m.rfind(b'one', 1, -2), -1) C:\Programs\Python38\lib\test\test_mmap.py: 302: self.assertEqual(m.rfind(bytearray(b'one')), 8) C:\Programs\Python38\lib\test\test_socket.py: 313: i = methodname.rfind('.') C:\Programs\Python38\lib\test\test_urllib2.py: 398: code = action[action.rfind(" ")+1:] C:\Programs\Python38\lib\urllib\parse.py: 384: i = url.find(';', url.rfind('/')) C:\Programs\Python38\lib\urllib\request.py: 2083: semi = type.rfind(';') C:\Programs\Python38\lib\warnings.py: 260: i = category.rfind(".") C:\Programs\Python38\lib\zipfile.py: 292: start = data.rfind(stringEndArchive) C:\Programs\Python38\lib\zipimport.py: 384: pos = data.rfind(STRING_END_ARCHIVE) Hits found: 136 (Hint: right-click to open locations.) -- Terry Jan Reedy

On Tue, Apr 23, 2019 at 1:02 PM MRAB <python@mrabarnett.plus.com> wrote:
Me neither, though for substring checks, reversing the string would be even more cumbersome (you'd have to reverse the query string too). My money is on "nobody uses this for lists". Some use cases for rindex() on strings that I found in a large codebase here include searching a pathname for the final slash, a list of comma-separated items for the last comma, a fully-qualified module name for the last period, and some ad-hoc parsing of other things. The "last separator" use cases are the most common and here rindex() sounds very useful. -- --Guido van Rossum (python.org/~guido) *Pronouns: he/him/his **(why is my pronoun here?)* <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-c...>

Hi all, Thanks for the explanation. Now I agree that the need for list.rindex() is not as common as str.rindex(). In fact, I only need list.rindex() when doing some algorithm problems. I guess that doesn't count as real need here. Best, John Lin Guido van Rossum <guido@python.org> 於 2019年4月24日 週三 上午4:20寫道:
participants (7)
-
Brett Cannon
-
Greg Ewing
-
Guido van Rossum
-
MRAB
-
Steven D'Aprano
-
Terry Reedy
-
林自均