how python interpreter treats the position of the function definition having default parameter
Tip for python beginners : If you use IDEs like pycharm - you can put a debugger and see what is happening with the variables.
We can get a better understanding of what is going on using the id(b)
which gets us the address of the particular object in memory:
Return the “identity” of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.
CPython implementation detail: This is the address of the object in memory.
Let me modify your code to the following :
b = 50
print("b=50 :", id(b))
def f(a, b=b):
print("b in the function f :", id(b))
print(id(b))
return a + b
b = 20
print("b=20 :", id(b))
print(f(1))
The output is as following:
b=50 : 4528710960
b=20 : 4528710000
b in the function f : 4528710960
4528710960
51
As you can see the b
inside the function and the b=50
have the same address.
When you do b=20
a new object was created.
In Python, (almost) everything is an object. What we commonly refer to as "variables" in Python are more properly called names. Likewise, "assignment" is really the binding of a name to an object. Each binding has a scope that defines its visibility, usually the block in which the name originates.
In python
When you do
b=50
a binding
of b to an int object is created in the scope of the block
When we later say b=20
the int object b=50
is unaffected. These both are essentially two different objects.
You can read more about it in these links.
- Is Python call-by-value or call-by-reference? Neither.
- Parameter Passing
- Python id()
Think of how the interpreter treats this. In the first case, def f(a, b=b)
is interpreted as def f(a, b=50)
since the value of b
in the current scope is 50
. As such, f(1)
assigns a
to 1
, and thus, a + b
= 1 + 50 = 51.
Similarly, in the second case, the value of b
in the current scope is 20 when the function is declared, so the definition is interpreted as def f(a, b=20)
. Therefore, f(1)
= 21.
The reason why the different placement of the function is resulting in different errors is because of the placement of the value 'b' as well.
Since the function 'f', is using a named parameter 'b', so it takes the first assignment of the variable 'b' as the argument/parameter to the function 'f'
For example,
b = 50
def f(a, b=b):
return a + b
b = 20
print(f(1))
As you pointed out, this results in the output 51
But if I were to change the code by a bit to
def f(a, b=b):
return a + b
b = 50
b = 20
print(f(1))
It would result in the following error:
def f(a, b=b):
NameError: name 'b' is not defined
Hence, we can deduce that the placement of the variable which is taken as a named parameter to the function is causing the difference in outputs.
You can also use the global variables for the same.