09/06/2024
Default Args Saga and why use None?
I know default args, but I haven’t dived deep into understanding how they work. I got into this rabbit-hole, while I was debugging some peculiar issue in one of my project.
In Python, default arguments are stored at the time the function is defined, not when it’s called. When you define a function with default arguments, Python evaluates the default argument expressions and binds the resulting objects to the function’s bytecode object.
Here’s how it works:
-
Function Definition: When you define a function with default arguments, Python evaluates the default argument expressions and binds the resulting objects to the function’s bytecode object. This happens only once, at the time of function definition.
def foo(x=[]): ...
-
Binding Default Values: The default argument values are stored in the function object’s
__defaults__
attribute as a tuple. For each default argument, its value is stored in the tuple at the corresponding position.foo.__defaults__ # Tuple containing default values
-
Execution: When the function is called without providing a value for a particular argument, Python uses the default value stored in the function’s
__defaults__
attribute.foo() # Uses the default value for x
-
Mutable Defaults: If the default value is mutable (e.g., a list or dictionary), changes to that object will persist across multiple function calls, as the same object is reused.
def foo(x=[]): x.append(1) return x print(foo.__defaults__) # ([], ) print(foo()) # [1] print(foo()) # [1, 1]
So, default arguments are captured and stored in the function object’s attributes at the time of function definition. This behavior is a result of Python’s approach to function definition and object binding.