@@ -19,20 +19,39 @@ Mutable Default Arguments
19
19
Seemingly the *most * common surprise new Python programmers encounter is
20
20
Python's treatment of mutable default arguments in function definitions.
21
21
22
- **What You Wrote **
22
+ What You Wrote
23
+ ~~~~~~~~~~~~~~
23
24
24
- .. code-block :: python
25
+ .. testcode ::
25
26
26
27
def append_to(element, to=[]):
27
28
to.append(element)
28
29
return to
29
30
30
- **What You Might Have Expected to Happen **
31
+ What You Might Have Expected to Happen
32
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
33
+
34
+ .. testcode ::
35
+
36
+ my_list = append_to(12)
37
+ print my_list
38
+
39
+ my_other_list = append_to(42)
40
+ print my_other_list
31
41
32
42
A new list is created each time the function is called if a second argument
33
- isn't provided.
43
+ isn't provided, so that the output is::
44
+
45
+ [12]
46
+ [42]
47
+
48
+ What Does Happen
49
+ ~~~~~~~~~~~~~~~~
50
+
51
+ .. testoutput ::
34
52
35
- **What Does Happen **
53
+ [12]
54
+ [12, 42]
36
55
37
56
A new list is created *once * when the function is defined, and the same list is
38
57
used in each successive call.
@@ -42,7 +61,8 @@ not each time the function is called (like it is in say, Ruby). This means that
42
61
if you use a mutable default argument and mutate it, you *will * and have
43
62
mutated that object for all future calls to the function as well.
44
63
45
- **What You Should Do Instead **
64
+ What You Should Do Instead
65
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
46
66
47
67
Create a new object each time the function is called, by using a default arg to
48
68
signal that no argument was provided (``None `` is often a good choice).
@@ -56,7 +76,8 @@ signal that no argument was provided (``None`` is often a good choice).
56
76
return to
57
77
58
78
59
- **When the Gotcha Isn't a Gotcha **
79
+ When the Gotcha Isn't a Gotcha
80
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
60
81
61
82
Sometimes you specifically can "exploit" (read: use as intended) this behavior
62
83
to maintain state between calls of a function. This is often done when writing
@@ -69,19 +90,41 @@ Late Binding Closures
69
90
Another common source of confusion is the way Python binds its variables in
70
91
closures (or in the surrounding global scope).
71
92
72
- **What You Wrote **
93
+ What You Wrote
94
+ ~~~~~~~~~~~~~~
73
95
74
- .. code-block :: python
96
+ .. testcode ::
75
97
76
- def create_adders ():
98
+ def create_multipliers ():
77
99
return [lambda x : i * x for i in range(5)]
78
100
79
- **What You Might Have Expected to Happen **
101
+ What You Might Have Expected to Happen
102
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
103
+
104
+ .. testcode ::
105
+
106
+ for multiplier in create_multipliers():
107
+ print multiplier(2)
80
108
81
109
A list containing five functions that each have their own closed-over ``i ``
82
- variable that multiplies their argument.
110
+ variable that multiplies their argument, producing::
111
+
112
+ 0
113
+ 2
114
+ 4
115
+ 6
116
+ 8
117
+
118
+ What Does Happen
119
+ ~~~~~~~~~~~~~~~~
120
+
121
+ .. testoutput ::
83
122
84
- **What Does Happen **
123
+ 8
124
+ 8
125
+ 8
126
+ 8
127
+ 8
85
128
86
129
Five functions are created, but all of them just multiply ``x `` by 4.
87
130
@@ -105,7 +148,8 @@ fact the same exact behavior is exhibited by just using an ordinary ``def``:
105
148
return i * x
106
149
yield adder
107
150
108
- **What You Should Do Instead **
151
+ What You Should Do Instead
152
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
109
153
110
154
Well. Here the general solution is arguably a bit of a hack. Due to Python's
111
155
afformentioned behavior concerning evaluating default arguments to functions
@@ -117,7 +161,8 @@ its arguments by using a default arg like so:
117
161
def create_adders ():
118
162
return [lambda x , i = i : i * x for i in range (5 )]
119
163
120
- **When the Gotcha Isn't a Gotcha **
164
+ When the Gotcha Isn't a Gotcha
165
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
121
166
122
167
When you want your closures to behave this way. Late binding is good in lots of
123
168
situations. Looping to create unique functions is unfortunately a case where
0 commit comments