On Mon, Jan 27, 2014 at 08:03:54PM -0800, Andrew Barnert wrote:
From: Ron Adam email@example.com
How about a keyword to specify which end to index from?
As a general rule, when you have a function that takes a parameter which selects between two different sets of behaviour, and you normally specify that parameter as a literal or constant known at edit time, then the function should be split into two.
# Good API string.upper(), string.lower()
# Bad API string.convert_case(to_upper=True|False)
sorted() and list.sort() (for example) are a counter-example. Sometimes you know which direction you want at edit-time, but there are many use-cases for leaving the decision to run-time. Nearly every application that sorts data lets the user decide which direction to sort.
In the case of replace/rreplace, it is more like the upper vs. lower situation than the sorted situation. For almost any reasonable use-case, you will know at edit-time whether you want to go from the left or from the right, so you'll specify the "direction" parameter as a edit-time literal or constant. The same applies to find/rfind.
When used, it would disable negative indexing as well.
Negative indexing is a standard Python feature. There is nothing wrong with negative indexing, no more than there is something wrong with zero-based positive indexing.
It's also irrelevant to the replace/rreplace example, since replace doesn't take start/end indexes, and presumably rreplace wouldn't either.
When not used the current behaviour with negative indexing would be the default.
direction=0 # The default with the current (or not specified) # negative indexing allowed.
direction=1 # From first. Negative indexing disallowed. direction=-1 # From last. Negative indexing disallowed.
And if you want to operate from the right, with negative indexing allowed? But really, having a flag to decide whether to allow negative indexing is silly. If you don't want negative indexes, just don't use them.
(A shorter key word would be nice, but I can't think of any that is as clear.)
Why does it have to be -1/0/1 instead of just True/False?
In which case we could use "reverse", the same name that's already used for similar things in other methods like list.sort (and that's implied in the current names "rfind", etc.).
sorted(alist, reverse=True) gives the same result as sorted(alist, reverse=False) only reversed. That is not the case here:
"Hello world".replace("o", "u", 1, reverse=True) # rreplace
ought to return "Hello wurld", not "dlrow ulleH".
The reason for turning off the negative indexing is it would also offer a way to
avoid some indexing bugs as well. (Using negative indexing with a reversed index is just asking for trouble I think.)
But str.rfind takes negative indices today:
>>> 'abccba'.rfind('b', -5, -3) 1
Why take away functionality that already works?
Exactly. Here, I agree strongly with Andrew. Negative indexing works perfectly well with find/rfind. Slices with negative strides are weird, but negative indexes are well-defined and easy to understand.
And of course str.find takes negative indices and that's actually used in some quick&dirty scripts:
>>> has_ext = path.find('.', -4)
Of course you could make an argument that any such scripts deserve to be broken…
It would be an awfully bogus argument. Negative indexes are a well-defined part of Python indexing semantics. One might as well argue that any scripts that rely on list slicing making a copy "deserve to be broken".