i = 5
def f(arg=i):
print(arg)
i = 6
f()
I am learning Python from the official documentation. There I find the above piece of code which I am unable to understand as to why 5 is printed instead of 6. I am relatively new to Python. Can somebody help me understand the concept?
In the past, the general strategy for setting defaults was to test parameter values in the function body and assign a value if they are undefined . In the following example, if no value is provided for b when multiply is called, b 's value would be undefined when evaluating a * b and multiply would return NaN .
When we define the default values for a function? Explanation: Default values for a function is defined when the function is declared inside a program.
In JavaScript, default function parameters allow you to initialize named parameters with default values if no values or undefined are passed into the function.
Python has a different way of representing syntax and default values for function arguments. Default values indicate that the function argument will take that value if no argument value is passed during the function call. The default value is assigned by using the assignment(=) operator of the form keywordname=value.
It's because default arguments are defined at function definition time, not function execution time. This is the same mechanism that drives the mutable default arg behavior as well You can change the __defaults__ and __kwdefaults__ attributes of the function object to dynamically change the default values. Show activity on this post.
The variable f was defined with the default of "123" at definition time. This can't be changed. Even with mutable defaults such as in this question: The default argument was already defined, and the name f was bound to the value [], that cannot be changed.
Why do variables not change their values after being called by a function in C++? I think I know what you are asking. Variables are not called by a function, they are passed to a function. There are three basic ways to do that: int F ( int x) - when you call this function a copy of your variable is placed on the stack (or, likely in a register).
Typically, you set a default value for a control only when you don't bind that control to a table field, or when you link to data in another table. In the Navigation Pane, right-click the form that you want to change, and then click Design View. Right-click the control that you want to change, and then click Properties or press F4.
def f(arg=i)
says "make me a function f
where the default value for arg
is whatever i
is right now". At the time of defining the function, i=5
.
i = 5
def f(arg=i)
print(arg)
The i
is evaluated at the time of definition, so the code above has the same meaning as the code below:
def f(arg=5)
print(arg)
This means that, when the function is called without arguments, arg
will have the value 5
, no matter what the value of i
is now.
In order to get what you want, just do the following:
def f(arg)
print(arg)
i = 6
f(i)
Because the function takes its default value on the first declaration of 'i'.
Change to i=6 on the first line if you want you code to print 6.
Hope I helped !
This is the difference between something being handled by reference vs by value. When you defined the function f
you told it to set the argument's default value to i
this is done by value, not by reference, so it took whatever the value of i
was at that time and set the default for the function to that. Changing the value of i
after that point does not change the value of arg
. If you want it to work that way you could do this:
i = 5
def f(arg = None):
if (arg = None)
arg = i
print(arg)
i = 6
f()
This lets you pass a value for arg
into the function as normal, but if you don't (or you explicitly pass None
) it updates arg
to the current value of i
if arg
is still None
(Python's version of NULL if you're familiar with other languages)
Something similar can be done using the or
operator, arg = arg or i
,but that will check if arg
is falsy, and when using integers like you are in your example, 0 will be caught by the check.
What others have said is true...the default is evaluated at the time of function creation, but it is not that it takes the "value of i" at the time of creation. The default is assigned the object referred to by "i" at the time of creation. This is an important point, because if that object is mutable, the default can be changed!
Here's what happens:
import inspect
i = 5 # name "i" refers to an immutable Python integer object of value 5.
print(f'i = {i} (id={id(i)})') # Note value and ID
# Create function "f" with a parameter whose default is the object
# referred to by name "i" *at this point*.
def f(arg=i):
print(f'arg = {arg} (id={id(arg)})')
# Use the inspect module to extract the defaults from the function.
# Note the value and ID
defaults = dict(inspect.getmembers(f))['__defaults__']
print(f'defaults = {defaults} (id={id(defaults[0])})')
# name "i" now refers to a different immutable Python integer object of value 6.
i = 6
print(f'i = {i} (id={id(i)})') # Note value and ID (changed!)
f() # default for function still referes to object 5.
f(i) # override the default with object currently referred to by name "i"
Output:
i = 5 (id=2731452426672) # Original object
defaults = (5,) (id=2731452426672) # default refers to same object
i = 6 (id=2731452426704) # Different object
arg = 5 (id=2731452426672) # f() default is the original object
arg = 6 (id=2731452426704) # f(i) parameter is different object
Now see the results of a mutable default:
import inspect
i = [5] # name "i" refers to an mutable Python list containing immutable integer object 5
print(f'i = {i} (id={id(i)})') # Note value and ID
# Create function "f" with a parameter whose default is the object
# referred to by name "i" *at this point*.
def f(arg=i):
print(f'arg = {arg} (id={id(arg)})')
# Use the inspect module to extract the defaults from the function.
# Note the value and ID
defaults = dict(inspect.getmembers(f))['__defaults__']
print(f'defaults = {defaults} (id={id(defaults[0])})')
# name "i" now refers to a different immutable Python integer object of value 6.
i[0] = 6 # MUTATE the content of the object "i" refers to.
print(f'i = {i} (id={id(i)})') # Note value and ID (UNCHANGED!)
f() # default for function still refers to original list object, but content changed!
i = [7] # Create a different list object
print(f'i = {i} (id={id(i)})') # Note value and ID (changed)
f(i) # override the default currently refered to by name "i"
Output:
i = [5] (id=2206901216704) # Original object
defaults = ([5],) (id=2206901216704) # default refers to original object
i = [6] (id=2206901216704) # Still original object, but content changed!
arg = [6] (id=2206901216704) # f() default refers to orginal object, but content changed!
i = [7] (id=2206901199296) # Create a new list object
arg = [7] (id=2206901199296) # f(i) parameter refers to new passed object.
This can have strange side effects if not understood well:
>>> def f(a,b=[]): # mutable default
... b.append(a)
... return b
...
>>> x = f(1)
>>> x
[1]
>>> y = f(2) # some would think this would return [2]
>>> y
[1, 2]
>>> x # x changed from [1] to [1,2] as well!
[1, 2]
Above, b
refers to the original default list object. Appending to it mutates the default list. Returning it makes x
refer to the same object. The default list now contains [1]
so appending in the 2nd call make it [1,2]
. y
refers to the same default object as x
so both names refer see the same object content.
To fix, make the default immutable and create a new list when the default is seen:
>>> def f(a,b=None):
... if b is None:
... b = []
... b.append(a)
... return b
...
>>> f(1)
[1]
>>> f(2)
[2]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With