Skip to content

Commit 83149c4

Browse files
warsawViicoshugovk
authored
PEP 769: Fix some typos and provide some clarity (#4192)
* Fix some typos and provide some clarity * Update peps/pep-0769.rst Co-authored-by: Victorien <65306057+Viicos@users.noreply.github.com> --------- Co-authored-by: Victorien <65306057+Viicos@users.noreply.github.com> Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
1 parent 25c9edb commit 83149c4

File tree

1 file changed

+59
-58
lines changed

1 file changed

+59
-58
lines changed

peps/pep-0769.rst

Lines changed: 59 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Python-Version: 3.14
1010
Abstract
1111
========
1212

13-
This proposal aims to enhance the ``operator`` module by adding a
13+
This proposal aims to enhance the :mod:`operator` module by adding a
1414
``default`` keyword argument to the ``attrgetter`` and ``itemgetter``
1515
functions. This addition would allow these functions to return a
1616
specified default value when the targeted attribute or item is missing,
@@ -48,7 +48,7 @@ value for all cases (more about this below in `Rejected Ideas
4848
Specification
4949
=============
5050

51-
Proposed behaviours:
51+
Proposed behaviors:
5252

5353
- **attrgetter**: ``f = attrgetter("name", default=XYZ)`` followed by
5454
``f(obj)`` would return ``obj.name`` if the attribute exists, else
@@ -67,7 +67,7 @@ No functionality change is incorporated if ``default`` is not used.
6767
Examples for attrgetter
6868
-----------------------
6969

70-
Current behaviour, no changes introduced::
70+
The current behavior is unchanged::
7171

7272
>>> class C:
7373
... class D:
@@ -95,7 +95,7 @@ Current behaviour, no changes introduced::
9595
File "<stdin>", line 1, in <module>
9696
AttributeError: type object 'D' has no attribute 'badname'
9797

98-
Using ``default``::
98+
With this PEP, using the proposed ``default`` keyword::
9999

100100
>>> attrgetter("D", default="noclass")(C)
101101
<class '__main__.C.D'>
@@ -114,7 +114,7 @@ Using ``default``::
114114
Examples for itemgetter
115115
-----------------------
116116

117-
Current behaviour, no changes introduced::
117+
The current behavior is unchanged::
118118

119119
>>> obj = ["foo", "bar", "baz"]
120120
>>> itemgetter(1)(obj)
@@ -131,7 +131,7 @@ Current behaviour, no changes introduced::
131131
IndexError: list index out of range
132132

133133

134-
Using ``default``::
134+
With this PEP, using the proposed ``default`` keyword::
135135

136136
>>> itemgetter(1, default="XYZ")(obj)
137137
'bar'
@@ -148,33 +148,33 @@ Using ``default``::
148148
About Possible Implementations
149149
------------------------------
150150

151-
For the case of ``attrgetter`` is quite direct: it implies using
152-
``getattr`` catching a possible ``AttributeError``. So
151+
The implementation of ``attrgetter`` is quite direct: it implies using
152+
``getattr`` and catching a possible ``AttributeError``. So
153153
``attrgetter("name", default=XYZ)(obj)`` would be like::
154154

155155
try:
156156
value = getattr(obj, "name")
157157
except (TypeError, IndexError, KeyError):
158158
value = XYZ
159159

160-
Note we cannot rely on using ``gettattr`` with a default value, as would
160+
Note we cannot rely on using ``getattr`` with a default value, as it would
161161
be impossible to distinguish what it returned on each step when an
162162
attribute chain is specified (e.g.
163163
``attrgetter("foo.bar.baz", default=XYZ)``).
164164

165-
For the case of ``itemgetter`` it's not that easy. The more
166-
straightforward way is similar to above, also simple to define and
165+
The implementation for ``itemgetter`` is not that easy. The more
166+
straightforward way is also simple to define and
167167
understand: attempting ``__getitem__`` and catching a possible exception
168-
(any of the three indicated in ``__getitem__`` reference). This way,
168+
(any of the three indicated in ``__getitem__`` `reference`_). This way,
169169
``itemgetter(123, default=XYZ)(obj)`` would be equivalent to::
170170

171171
try:
172172
value = obj[123]
173173
except (TypeError, IndexError, KeyError):
174174
value = XYZ
175175

176-
However, this would be not as efficient as we'd want for particular cases,
177-
e.g. using dictionaries where particularly good performance is desired. A
176+
However, this would be not as efficient as we'd want for certain cases,
177+
e.g. using dictionaries where better performance is possible. A
178178
more complex alternative would be::
179179

180180
if isinstance(obj, dict):
@@ -185,16 +185,16 @@ more complex alternative would be::
185185
except (TypeError, IndexError, KeyError):
186186
value = XYZ
187187

188-
Better performance, more complicated to implement and explain. This is
188+
While this provides better performance, it is more complicated to implement and explain. This is
189189
the first case in the `Open Issues <PEP 769 Open Issues_>`__ section later.
190190

191191

192192
Corner Cases
193193
------------
194194

195-
Providing a ``default`` option would only work when accessing to the
196-
item/attribute would fail in a regular situation. In other words, the
197-
object accessed should not handle defaults theirselves.
195+
Providing a ``default`` option would only work when accessing the
196+
item/attribute would fail in the normal case. In other words, the
197+
object accessed should not handle defaults itself.
198198

199199
For example, the following would be redundant/confusing because
200200
``defaultdict`` will never error out when accessing the item::
@@ -205,8 +205,8 @@ For example, the following would be redundant/confusing because
205205
>>> itemgetter("foo", default=-1)(dd)
206206
0
207207

208-
The same applies to any user built object that overloads ``__getitem__``
209-
or ``__getattr__`` implementing fallbacks.
208+
The same applies to any user defined object that overloads ``__getitem__``
209+
or ``__getattr__`` implementing its own fallbacks.
210210

211211

212212
.. _PEP 769 Rejected Ideas:
@@ -221,30 +221,29 @@ The idea of allowing multiple default values for multiple attributes or
221221
items was considered.
222222

223223
Two alternatives were discussed, using an iterable that must have the
224-
same quantity of items than parameters given to
224+
same quantity of items as parameters given to
225225
``attrgetter``/``itemgetter``, or using a dictionary with keys matching
226226
those names passed to ``attrgetter``/``itemgetter``.
227227

228-
The really complex thing to solve in these casse, that would make the
229-
feature hard to explain and with confusing corners, is what would happen
230-
if an iterable or dictionary is the *unique* default desired for all
228+
The really complex thing to solve here (making the
229+
feature hard to explain and with confusing corner cases), is what would happen
230+
if an iterable or dictionary is the *actual* default desired for all
231231
items. For example::
232232

233-
>>> itemgetter("a", default=(1, 2)({})
233+
>>> itemgetter("a", default=(1, 2))({})
234234
(1, 2)
235235
>>> itemgetter("a", "b", default=(1, 2))({})
236236
((1, 2), (1, 2))
237237

238238
If we allow "multiple default values" using ``default``, the first case
239-
in the example above would raise an exception because more items in the
240-
default than names, and the second case would return ``(1, 2))``. This is
241-
why emerged the possibility of using a different name for multiple
242-
defaults (``defaults``, which is expressive but maybe error prone because
243-
too similar to ``default``).
239+
in the example above would raise an exception because there are more items
240+
than names in the default, and the second case would return ``(1, 2))``. This is
241+
why we considered the possibility of using a different name for multiple
242+
defaults (e.g. ``defaults``, which is expressive but maybe error prone because
243+
it is too similar to ``default``).
244244

245-
As part of this conversation there was another proposal that would enable
246-
multiple defaults, which is allowing combinations of ``attrgetter`` and
247-
``itemgetter``, e.g.::
245+
Another proposal that would enable multiple defaults, is allowing
246+
combinations of ``attrgetter`` and ``itemgetter``, e.g.::
248247

249248
>>> ig_a = itemgetter("a", default=1)
250249
>>> ig_b = itemgetter("b", default=2)
@@ -254,20 +253,20 @@ multiple defaults, which is allowing combinations of ``attrgetter`` and
254253
>>> ig_combined({})
255254
(1, 2)
256255

257-
However, combining ``itemgetter`` or ``attrgetter`` is a totally new
258-
behaviour very complex to define, not impossible, but beyond the scope of
256+
However, combining ``itemgetter`` or ``attrgetter`` is totally new
257+
behavior and very complex to define. While not impossible, it is beyond the scope of
259258
this PEP.
260259

261-
At the end having multiple default values was deemed overly complex and
260+
In the end, having multiple default values was deemed overly complex and
262261
potentially confusing, and a single ``default`` parameter was favored for
263262
simplicity and predictability.
264263

265264

266265
Tuple Return Consistency
267266
------------------------
268267

269-
Another rejected proposal was adding a flag to always return tuple
270-
regardless of how many keys/names/indices were sourced to arguments.
268+
Another rejected proposal was adding a flag to always return a tuple
269+
regardless of how many keys/names/indices were given.
271270
E.g.::
272271

273272
>>> letters = ["a", "b", "c"]
@@ -276,8 +275,8 @@ E.g.::
276275
>>> itemgetter(1, 2, return_tuple=True)(letters)
277276
('b', 'c')
278277

279-
This would be of a little help for multiple default values consistency,
280-
but requires further discussion and for sure is out of the scope of this
278+
This would be of little help for multiple default values consistency,
279+
requiring further discussion, and is out of the scope of this
281280
PEP.
282281

283282

@@ -286,39 +285,39 @@ PEP.
286285
Open Issues
287286
===========
288287

289-
Behaviour Equivalence for ``itemgetter``
290-
----------------------------------------
288+
Behavior Equivalence for ``itemgetter``
289+
---------------------------------------
291290

292-
We need to define how ``itemgetter`` would behave, if just attempt to
293-
access the item and capture exceptions no matter which the object, or
294-
validate first if the object provides a ``get`` method and use it to
295-
retrieve the item with a default. See examples in the `About Possible
291+
For ``itemgetter``, should it just attempt to
292+
access the item and capture exceptions regardless of the object's API, or
293+
should it first validate that the object provides a ``get`` method, and if so use it to
294+
retrieve the item with a default? See examples in the `About Possible
296295
Implementations <PEP 769 About Possible Implementations_>`__ subsection
297296
above.
298297

299298
This would help performance for the case of dictionaries, but would make
300299
the ``default`` feature somewhat more difficult to explain, and a little
301-
confusing if some object that is not a dictionary but provides a ``get``
302-
method is used. Alternatively, we could call ``.get`` *only* if the
300+
confusing if some object that is not a dictionary but still provides a ``get``
301+
method. Alternatively, we could call ``.get`` *only* if the
303302
object is an instance of ``dict``.
304303

305-
In any case, a desirable situation is that we do *not* affect performance
304+
In any case, it is desirable that we do *not* affect performance
306305
at all if the ``default`` is not triggered. Checking for ``.get`` would
307-
get the default faster in case of dicts, but implies doing a verification
308-
in all cases. Using the try/except model would make it not as fast as it
309-
could in the case of dictionaries, but would not introduce delays if the
306+
be faster for dicts, but implies doing a verification
307+
in all cases. Using the try/except model would make it less efficient as possible
308+
in the case of dictionaries, but only if the
310309
default is not triggered.
311310

312311

313312
Add a Default to ``getitem``
314313
----------------------------
315314

316-
It was proposed that we could also enhance ``getitem``, as part of the of
317-
this PEP, adding ``default`` also to it.
315+
It was proposed that we could also enhance ``getitem``, as part of
316+
this PEP, adding the ``default`` keyword to that function as well.
318317

319318
This will not only improve ``getitem`` itself, but we would also gain
320319
internal consistency in the ``operator`` module and in comparison with
321-
the ``getattr`` builtin function that also has a default.
320+
the ``getattr`` builtin function, which also has a default.
322321

323322
The definition could be as simple as the try/except proposed above, so
324323
doing ``getitem(obj, name, default)`` would be equivalent to::
@@ -328,15 +327,15 @@ doing ``getitem(obj, name, default)`` would be equivalent to::
328327
except (TypeError, IndexError, KeyError):
329328
result = default
330329

331-
(However see previous open issue about special case for dictionaries)
330+
(However see previous open issue about special case for dictionaries.)
332331

333332

334333
How to Teach This
335334
=================
336335

337-
As the basic behaviour is not modified, this new ``default`` can be
336+
As the basic behavior is not modified, this new ``default`` can be
338337
avoided when teaching ``attrgetter`` and ``itemgetter`` for the first
339-
time, and can be introduced only when the functionality need arises.
338+
time. It can be introduced only when the functionality is needed.
340339

341340

342341
Backwards Compatibility
@@ -355,6 +354,8 @@ Security Implications
355354
Introducing a ``default`` parameter does not inherently introduce
356355
security vulnerabilities.
357356

357+
.. _reference: https://docs.python.org/3/reference/datamodel.html#object.__getitem__
358+
.. _module: https://docs.python.org/3/library/operator.html
358359

359360
Copyright
360361
=========

0 commit comments

Comments
 (0)