I like how that would take the pressure off of the Python sample. How's something like this?
Specification
=============
The builtin ``str`` class will gain two new methods which will behave
as follows when ``type(self) is str``::
def removeprefix(self: str, prefix: str, /) -> str:
if self.startswith(prefix):
return self[len(prefix):]
else:
return self
def removesuffix(self: str, suffix: str, /) -> str:
if suffix and self.endswith(suffix):
return self[:-len(suffix)]
else:
return self
These methods, even when called on ``str`` subclasses, should always
return base ``str`` objects. One should not rely on the behavior
of ``self`` being returned (as in ``s.removesuffix('') is s``) -- this
optimization should be considered an implementation detail.
I'd suggest to drop the last sentence ("One should ... detail.") and instead write 'return self[:]' in the methods.
To test
whether any affixes were removed during the call, one may use the
constant-time behavior of comparing the lengths of the original and
new strings::
>>> string = 'Python String Input'
>>> new_string = string.removeprefix('Py')
>>> modified = (len(string) != len(new_string))
>>> modified
True
If I saw that in a code review I'd flag it for non-obviousness. One should use 'string != new_string' *unless* there is severe pressure to squeeze every nanosecond out of this particular code (and it better be inside an inner loop).
One may also continue using ``startswith()`` and ``endswith()``
methods for control flow instead of testing the lengths as above.
That's worse, in a sense, since "foofoobar".removeprefix("foo") returns "foobar" which still starts with "foo".
Note that without the check for the truthiness of ``suffix``,
``s.removesuffix('')`` would be mishandled and always return the empty
string due to the unintended evaluation of ``self[:-0]``.
That's a good one (I started suggesting dropping that when I read this :-) but maybe it ought to go in a comment (and shorter -- at most one line).
Methods with the corresponding semantics will be added to the builtin
``bytes`` and ``bytearray`` objects. If ``b`` is either a ``bytes``
or ``bytearray`` object, then ``b.removeprefix()`` and ``b.removesuffix()``
will accept any bytes-like object as an argument. Although the methods
on the immutable ``str`` and ``bytes`` types may make the aforementioned
optimization of returning the original object, ``bytearray.removeprefix()``
and ``bytearray.removesuffix()`` should *always* return a copy, never the
original object.
This could also be simplified by writing 'return self[:]'.
The two methods will also be added to ``collections.UserString``, with
similar behavior.
My hesitation to write "return self" is resolved by saying that it should not be relied on, so I think this is a win.
Writing 'return self[:]' seems to say the same thing in fewer words though. :-)