Common Pitfalls
Global variables
A common problem when accessing variables from the global
scope is that setting a variable makes it local, unless you use the global
keyword.
Note: It’s better to avoid using global variables.
x = 10
def foo():
x += 1
print(x)
foo() # Error
Pass by reference with mutable variables
When you do this x = y
, both x
and y
will point to the same object in memory. So, modifying x
will also modify y
.
To avoid this, you can use the
copy
package usingdeepcopy
.
x = [1, 2, 3]
y = x
x.append(4)
print(y) # [1, 2, 3, 4]
Mutable function default arguments
When you use mutable objects as default arguments, they are shared across all calls to the function. E.g. lists, dicts, sets, class instance etc.
To avoid this, you can use
None
as the default value and then assign the default value inside the function.
def foo(x=[]):
x.append(1)
print(x)
foo() # [1]
foo() # [1, 1]
Modifying while iterating
While iterating through some mutable objects such as dict and sets, you can’t modify them. Will raise a RuntimeError
.
To avoid this, you can create a copy of the object and iterate through it.
d = {1: 'a', 2: 'b'}
for key in d:
if key == 1:
del d[key] # RuntimeError
Late binding and closures
When you use a loop to create a list of functions, the loop variable is bound to the function at the time of execution, not at the time of creation.
To avoid this, you can use default arguments to bind the value at the time of creation.
def create_functions():
return [lambda: i for i in range(3)]
# List comprehension to create functions with i
# Each lambda function is supposed to return the value of i from the range 0 to 2.
# However, the value of i is not bound at the time of creation, but at the time of execution. Which is 2. each lambda captures the reference to i.
for func in create_functions():
print(func()) # 2 2 2