PEP 616: Fix behavior of code snippets (#1336)
This commit is contained in:
parent
7a2c2168b6
commit
dcb29f4019
58
pep-0616.rst
58
pep-0616.rst
|
@ -52,7 +52,7 @@ following behavior::
|
|||
self_str = str(self)
|
||||
|
||||
if isinstance(prefix, tuple):
|
||||
for option in prefix:
|
||||
for option in tuple(prefix):
|
||||
if not isinstance(option, str):
|
||||
raise TypeError()
|
||||
option_str = str(option)
|
||||
|
@ -79,12 +79,14 @@ following behavior::
|
|||
self_str = str(self)
|
||||
|
||||
if isinstance(suffix, tuple):
|
||||
for option in suffix:
|
||||
for option in tuple(suffix):
|
||||
if not isinstance(option, str):
|
||||
raise TypeError()
|
||||
option_str = str(option)
|
||||
|
||||
if option_str and self_str.endswith(option_str):
|
||||
if not option_str:
|
||||
return self_str[:]
|
||||
if self_str.endswith(option_str):
|
||||
return self_str[:-len(option_str)]
|
||||
|
||||
return self_str[:]
|
||||
|
@ -98,23 +100,24 @@ following behavior::
|
|||
else:
|
||||
return self_str[:]
|
||||
|
||||
Note that without the check for the truthyness of suffixes,
|
||||
``s.cutsuffix('')`` would be mishandled and always return the empty
|
||||
|
||||
Note that without the check for the truthyness of suffixes,
|
||||
``s.cutsuffix('')`` would be mishandled and always return the empty
|
||||
string due to the unintended evaluation of ``self[:-0]``.
|
||||
|
||||
Methods with the corresponding semantics will be added to the builtin
|
||||
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.cutsuffix()`` and ``b.cutprefix()``
|
||||
will accept any bytes-like object or tuple of bytes-like objects as an
|
||||
argument. The one-at-a-time checking of types matches the implementation
|
||||
of ``startswith()`` and ``endswith()`` methods.
|
||||
|
||||
The ``self_str[:]`` copying behavior in the code ensures that the
|
||||
The ``self_str[:]`` copying behavior in the code ensures that the
|
||||
``bytearray`` methods do not return ``self``, but it does not preclude
|
||||
the ``str`` and ``bytes`` methods from returning ``self``. Because
|
||||
``str`` and ``bytes`` instances are immutable, the ``cutprefix()``
|
||||
and ``cutsuffix()`` methods on these objects may (but are not
|
||||
required to) make the optimization of returning ``self`` if
|
||||
required to) make the optimization of returning ``self`` if
|
||||
``type(self) is str`` (``type(self) is bytes`` respectively)
|
||||
and the given affixes are not found, or are empty. As such, the
|
||||
following behavior is considered a CPython implementation detail, and
|
||||
|
@ -142,6 +145,7 @@ methods for control flow instead of testing the lengths as above.
|
|||
The two methods will also be added to ``collections.UserString``, with
|
||||
similar behavior.
|
||||
|
||||
|
||||
Motivating examples from the Python standard library
|
||||
====================================================
|
||||
|
||||
|
@ -149,17 +153,17 @@ The examples below demonstrate how the proposed methods can make code
|
|||
one or more of the following:
|
||||
|
||||
1. Less fragile:
|
||||
|
||||
|
||||
The code will not depend on the user to count the length of a literal.
|
||||
|
||||
2. More performant:
|
||||
|
||||
|
||||
The code does not require a call to the Python built-in ``len``
|
||||
function, nor to the more expensive ``str.replace()``
|
||||
method.
|
||||
|
||||
3. More descriptive:
|
||||
|
||||
|
||||
The methods give a higher-level API for code readability, as
|
||||
opposed to the traditional method of string slicing.
|
||||
|
||||
|
@ -231,9 +235,6 @@ cookiejar.py
|
|||
test_concurrent_futures.py
|
||||
--------------------------
|
||||
|
||||
In the following example, the meaning of the code changes slightly,
|
||||
but in context, it behaves the same.
|
||||
|
||||
- Current::
|
||||
|
||||
if name.endswith(('Mixin', 'Tests')):
|
||||
|
@ -258,13 +259,14 @@ Expand the lstrip and rstrip APIs
|
|||
---------------------------------
|
||||
|
||||
Because ``lstrip`` takes a string as its argument, it could be viewed
|
||||
as taking an iterable of length-1 strings. The API could therefore be
|
||||
generalized to accept any iterable of strings, which would be
|
||||
successively removed as prefixes. While this behavior would be
|
||||
consistent, it would not be obvious for users to have to call
|
||||
``'foobar'.cutprefix(('foo,))`` for the common use case of a
|
||||
as taking an iterable of length-1 strings. The API could therefore be
|
||||
generalized to accept any iterable of strings, which would be
|
||||
successively removed as prefixes. While this behavior would be
|
||||
consistent, it would not be obvious for users to have to call
|
||||
``'foobar'.lstrip(('foo',))`` for the common use case of a
|
||||
single prefix.
|
||||
|
||||
|
||||
Remove multiple copies of a prefix
|
||||
----------------------------------
|
||||
|
||||
|
@ -272,20 +274,20 @@ This is the behavior that would be consistent with the aforementioned
|
|||
expansion of the ``lstrip``/``rstrip`` API -- repeatedly applying the
|
||||
function until the argument is unchanged. This behavior is attainable
|
||||
from the proposed behavior via by the following::
|
||||
|
||||
>>> s = 'foobar' * 100 + 'bar'
|
||||
>>> prefixes = ('bar', 'foo')
|
||||
|
||||
>>> s = 'FooBar' * 100 + 'Baz'
|
||||
>>> prefixes = ('Bar', 'Foo')
|
||||
>>> while len(s) != len(s := s.cutprefix(prefixes)): pass
|
||||
>>> s
|
||||
'bar'
|
||||
'Baz'
|
||||
|
||||
or the more obvious and readable alternative::
|
||||
|
||||
>>> s = 'foo' * 100 + 'bar'
|
||||
>>> prefixes = ('bar', 'foo')
|
||||
>>> s = 'FooBar' * 100 + 'Baz'
|
||||
>>> prefixes = ('Bar', 'Foo')
|
||||
>>> while s.startswith(prefixes): s = s.cutprefix(prefixes)
|
||||
>>> s
|
||||
'bar'
|
||||
'Baz'
|
||||
|
||||
|
||||
Raising an exception when not found
|
||||
|
@ -312,7 +314,7 @@ of ``cutprefix`` (the same arguments hold for ``cutsuffix``).
|
|||
|
||||
- ``lstrip(string=...)``
|
||||
|
||||
This would avoid adding a new method, but for different
|
||||
This would avoid adding a new method, but for different
|
||||
behavior, it's better to have two different methods than one
|
||||
method with a keyword argument that select the behavior.
|
||||
|
||||
|
@ -363,7 +365,7 @@ References
|
|||
(https://mail.python.org/archives/list/python-dev@python.org/thread/OJDKRIESKGTQFNLX6KZSGKU57UXNZYAN/#CYZUFFJ2Q5ZZKMJIQBZVZR4NSLK5ZPIH)
|
||||
.. [7] [Python-Dev] "strip behavior provides inconsistent results with certain strings"
|
||||
(https://mail.python.org/archives/list/python-dev@python.org/thread/ZWRGCGANHGVDPP44VQKRIYOYX7LNVDVG/#ZWRGCGANHGVDPP44VQKRIYOYX7LNVDVG)
|
||||
.. [#confusion] Comment listing Bug Tracker and StackOverflow issues
|
||||
.. [#confusion] Comment listing Bug Tracker and StackOverflow issues
|
||||
(https://mail.python.org/archives/list/python-ideas@python.org/message/GRGAFIII3AX22K3N3KT7RB4DPBY3LPVG/)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue