Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I change the default value of a function after it was defined?

Tags:

python

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?

like image 817
Gaurav Khandelwal Avatar asked Jan 18 '21 18:01

Gaurav Khandelwal


People also ask

How do you define the default value of a function parameter?

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 .

Can we define the default values for a function?

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.

Does JavaScript allow you to set default parameter values when defining a function?

In JavaScript, default function parameters allow you to initialize named parameters with default values if no values or undefined are passed into the function.

How do I change the default value of a variable in Python?

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.

Why can't I change the default values of default arguments dynamically?

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.

Why can't I change the default value of the variable f?

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 after being called by a function?

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).

How do I set a default value for a control?

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.


5 Answers

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.

like image 110
Ted Brownlow Avatar answered Nov 02 '22 22:11

Ted Brownlow


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)
like image 35
altermetax Avatar answered Nov 03 '22 00:11

altermetax


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 !

like image 36
Unguest Avatar answered Nov 02 '22 23:11

Unguest


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.

like image 23
Andrew Avatar answered Nov 02 '22 22:11

Andrew


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]
like image 29
Mark Tolonen Avatar answered Nov 03 '22 00:11

Mark Tolonen