-
Notifications
You must be signed in to change notification settings - Fork 0
3. Common Pitfalls
Kamal Banga edited this page Aug 28, 2018
·
15 revisions
a = b = [1,2]
a.append(3)
What is b
? It's [1,2,3]
.
a = [1,2]
b = a.copy() # deep copy
a.append(3)
Now, b
is still [1,2]
.
def append5(data=[]):
data.append(5)
return data
Using this append5
method results in an astonishing behaviour
>>> append5()
[5]
>>> append5()
[5, 5]
>>> append5()
[5, 5, 5]
❗️❓😳What just happened?
🚫Lesson: Don't use mutable values as default parameter values
Let's say we want a running average and we implement it using a class
class Averager:
def __init__(self):
self.series = []
def __call__(self, num):
self.series.append(num)
return sum(self.series)/len(self.series)
This can be used as
>>> avg = Averager()
>>> avg(10)
10.0
>>> avg(11)
10.5
>>> avg(12)
11.0
Same thing can be achieved using a closure
def make_averager():
series = []
def average(num):
series.append(num)
return sum(series)/len(series)
return average
It too achieves the same purpose
>>> avg = make_averager()
>>> avg(10)
10.0
>>> avg(11)
10.5
>>> avg(12)
11.0
Now, let's say we rewrite our make_averager
as
def make_averager():
count = 0
total = 0
def average(num):
count += 1
total += num
return total/count
return average
Trying to do the same thing leads us to UnboundLocalError
avg(10)
UnboundLocalError: local variable 'count' referenced before assignment
❗️❓😧