Skip to content

3. Common Pitfalls

Kamal Banga edited this page Aug 28, 2018 · 15 revisions

List Copy Reference

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].


Mutable and Immutables

Mutable default parameter value

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

Closures

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

❗️❓😧

Direct links

Iterators

Bell Curve

Clone this wiki locally