forked from yasoob/intermediatePython
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmutation.html
More file actions
136 lines (114 loc) · 7.5 KB
/
Copy pathmutation.html
File metadata and controls
136 lines (114 loc) · 7.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Mutation</title>
<link rel="stylesheet" href="_static/epub.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
</head>
<body role="document">
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="__slots__magic.html" title="__slots__ Magic"
accesskey="N">next</a></li>
<li class="right" >
<a href="global_&_return.html" title="Global & Return"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Python Tips 0.1 documentation</a> »</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="body" role="main">
<div class="section" id="mutation">
<h1>Mutation</h1>
<p>The mutable and immutable datatypes in Python cause a lot of headache
for new programmers. In simple words, mutable means ‘able to be changed’
and immutable means ‘constant’. Want your head to spin? Consider this
example:</p>
<div class="code python highlight-python"><div class="highlight"><pre><span class="n">foo</span> <span class="o">=</span> <span class="p">[</span><span class="s">'hi'</span><span class="p">]</span>
<span class="k">print</span><span class="p">(</span><span class="n">foo</span><span class="p">)</span>
<span class="c"># Output: ['hi']</span>
<span class="n">bar</span> <span class="o">=</span> <span class="n">foo</span>
<span class="n">bar</span> <span class="o">+=</span> <span class="p">[</span><span class="s">'bye'</span><span class="p">]</span>
<span class="k">print</span><span class="p">(</span><span class="n">foo</span><span class="p">)</span>
<span class="c"># Output: ['hi', 'bye']</span>
</pre></div>
</div>
<p>What just happened? We were not expecting that! We were expecting
something like this:</p>
<div class="code python highlight-python"><div class="highlight"><pre><span class="n">foo</span> <span class="o">=</span> <span class="p">[</span><span class="s">'hi'</span><span class="p">]</span>
<span class="k">print</span><span class="p">(</span><span class="n">foo</span><span class="p">)</span>
<span class="c"># Output: ['hi']</span>
<span class="n">bar</span> <span class="o">=</span> <span class="n">foo</span>
<span class="n">bar</span> <span class="o">+=</span> <span class="p">[</span><span class="s">'bye'</span><span class="p">]</span>
<span class="k">print</span><span class="p">(</span><span class="n">foo</span><span class="p">)</span>
<span class="c"># Output: ['hi']</span>
<span class="k">print</span><span class="p">(</span><span class="n">bar</span><span class="p">)</span>
<span class="c"># Output: ['hi', 'bye']</span>
</pre></div>
</div>
<p>It’s not a bug. It’s mutability in action. Whenever you assign a
variable to another variable of mutable datatype, any changes to the
data are reflected by both variables. The new variable is just an alias
for the old variable. This is only true for mutable datatypes. Here is a
gotcha involving functions and mutable data types:</p>
<div class="code python highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">add_to</span><span class="p">(</span><span class="n">num</span><span class="p">,</span> <span class="n">target</span><span class="o">=</span><span class="p">[]):</span>
<span class="n">target</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">num</span><span class="p">)</span>
<span class="k">return</span> <span class="n">target</span>
<span class="n">add_to</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="c"># Output: [1]</span>
<span class="n">add_to</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="c"># Output: [1, 2]</span>
<span class="n">add_to</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="c"># Output: [1, 2, 3]</span>
</pre></div>
</div>
<p>You might have expected it to behave differently. You might be expecting
that a fresh list would be created when you call <code class="docutils literal"><span class="pre">add_to</span></code> like this:</p>
<div class="code python highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">add_to</span><span class="p">(</span><span class="n">num</span><span class="p">,</span> <span class="n">target</span><span class="o">=</span><span class="p">[]):</span>
<span class="n">target</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">num</span><span class="p">)</span>
<span class="k">return</span> <span class="n">target</span>
<span class="n">add_to</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="c"># Output: [1]</span>
<span class="n">add_to</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="c"># Output: [2]</span>
<span class="n">add_to</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="c"># Output: [3]</span>
</pre></div>
</div>
<p>Well again it is the mutability of lists which causes this pain. In
Python the default arguments are evaluated once when the function is
defined, not each time the function is called. You should never define
default arguments of mutable type unless you know what you are doing.
You should do something like this:</p>
<div class="code python highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">add_to</span><span class="p">(</span><span class="n">element</span><span class="p">,</span> <span class="n">target</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
<span class="k">if</span> <span class="n">target</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
<span class="n">target</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">target</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">element</span><span class="p">)</span>
<span class="k">return</span> <span class="n">target</span>
</pre></div>
</div>
<p>Now whenever you call the function without the <code class="docutils literal"><span class="pre">target</span></code> argument, a
new list is created. For instance:</p>
<div class="code python highlight-python"><div class="highlight"><pre><span class="n">add_to</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span>
<span class="c"># Output: [42]</span>
<span class="n">add_to</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span>
<span class="c"># Output: [42]</span>
<span class="n">add_to</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span>
<span class="c"># Output: [42]</span>
</pre></div>
</div>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer" role="contentinfo">
© Copyright 2015, Muhammad Yasoob Ullah Khalid.
</div>
</body>
</html>