Dark theme

Key ideas in depth: Mutable vs immutable defaults; variables in methods


Mutable vs immutable defaults

Note that Python runs through all the functions creating parameter variables for them before it uses them. This means that default values are created then rather than each time the function runs (as is the case in some other languages). This means that for mutable defaults where the interior of the variable isn't recreated on assignment, the same mutable content is used each time.

There are some uses for this:

def count (count=[0]):
    count[0] += 1
    return count[0]

a = count()
a = count()
print(a)

But it opens up the possibility for some horrible mistakes so generally mutable defaults should be avoided. Instead, the recommendation is to create a new mutable outside of the definition if the parameter is not filled:

def func(listA=None):
    if listA is None:
        listA = []


Variables in methods

The fact that variables close up their scope when assigned has some strange behaviours associated with it. Of these, the most strange is this:

b = 10
def a ():
    print(b)
    b = 20 # Adding this line makes
        # the line above fail.

print(b) # This would print 10.
a()
print(b)

The reason is that Python scans blocks before running them and assumes any variable label assigned within a block is local to that block. This effects the whole block before and after, so the b in the function is different from that outside. At that point, the print(b) is trying to use a variable before a value has been assigned to it.

For a nice coverage of this issue, see Fluent Python on the textbook list. Unhelpfully, the documentation itself just says: "If a name binding operation occurs anywhere within a code block, all uses of the name within the block are treated as references to the current block. This can lead to errors when a name is used within a block before it is bound. This rule is subtle. Python lacks declarations and allows name binding operations to occur anywhere within a code block. The local variables of a code block can be determined by scanning the entire text of the block for name binding operations."