@@ -12,18 +12,23 @@ Post-History: 28-Feb-2018, 02-Mar-2018, 23-Mar-2018
12
12
Abstract
13
13
========
14
14
15
- Programming is all about reusing code rather than duplicating it. When
16
- an expression needs to be used twice in quick succession but never again,
17
- it is convenient to assign it to a temporary name with small scope.
18
- By permitting name bindings to exist within a single statement only, we
19
- make this both convenient and safe against name collisions.
15
+ This is a proposal for permitting temporary name bindings
16
+ which are limited to a single statement.
20
17
21
18
22
19
Rationale
23
20
=========
24
21
25
- When a subexpression is used multiple times in a list comprehension, there
26
- are currently several ways to spell this, none of which is universally
22
+ Programmers generally prefer reusing code rather than duplicating it. When
23
+ an expression needs to be used twice in quick succession but never again,
24
+ it is convenient to assign it to a temporary name with small scope.
25
+ By permitting name bindings to exist within a single statement only, we
26
+ make this both convenient and safe against name collisions.
27
+
28
+ This is particularly notable in list/dict/set comprehensions and generator
29
+ expressions, where refactoring a subexpression into an assignment statement
30
+ is not possible. There are currently several ways to create a temporary name
31
+ binding inside a list comprehension, none of which is universally
27
32
accepted as ideal. A statement-local name allows any subexpression to be
28
33
temporarily captured and then used multiple times.
29
34
@@ -43,7 +48,13 @@ and ``NAME`` is a simple name.
43
48
44
49
The value of such a named expression is the same as the incorporated
45
50
expression, with the additional side-effect that NAME is bound to that
46
- value for the remainder of the current statement.
51
+ value for the remainder of the current statement. For example::
52
+
53
+ # Similar to the boolean 'or' but checking for None specifically
54
+ x = "default" if (spam().ham as eggs) is None else eggs
55
+
56
+ # Even complex expressions can be built up piece by piece
57
+ y = ((spam() as eggs), (eggs.method() as cheese), cheese[eggs])
47
58
48
59
Just as function-local names shadow global names for the scope of the
49
60
function, statement-local names shadow other names for that statement.
@@ -252,14 +263,14 @@ Both of these are forbidden; creating SLNBs in the headers of these statements
252
263
will result in a SyntaxError.
253
264
254
265
255
- Alternative proposals
256
- =====================
266
+ Alternative proposals and variants
267
+ ==================================
257
268
258
269
Proposals broadly similar to this one have come up frequently on python-ideas.
259
270
Below are a number of alternative syntaxes, some of them specific to
260
271
comprehensions, which have been rejected in favour of the one given above.
261
272
262
- 1. ``where ``, ``let ``, ``given ``::
273
+ 1. ``where ``, ``let ``, or ``given ``, in comprehensions only ::
263
274
264
275
stuff = [(y, x/y) where y = f(x) for x in range(5)]
265
276
stuff = [(y, x/y) let y = f(x) for x in range(5)]
@@ -337,6 +348,15 @@ comprehensions, which have been rejected in favour of the one given above.
337
348
``f(x) < 0 `` and you want to capture the value of ``f(x) ``). It also has
338
349
no benefit to list comprehensions.
339
350
351
+ 8. Adding a ``where: `` to any statement to create local name bindings::
352
+
353
+ value = x**2 + 2*x where:
354
+ x = spam(1, 4, 7, q)
355
+
356
+ Execution order is inverted (the indented body is performed first, followed
357
+ by the "header"). This requires a new keyword, unless an existing keyword
358
+ is repurposed (most likely ``with:``).
359
+
340
360
341
361
Discrepancies in the current implementation
342
362
===========================================
0 commit comments