简体   繁体   中英

How to change default value of optional function parameter

I need to change the global variable S at a.py from b.py , but it is used as a default value in a function at a.py .

a.py

S = "string"


def f(s=S):
    print(s)
    print(S)

b.py

import a


def main():
    a.S = "another string"
    a.f()


if __name__ == "__main__":
    main()

python b.py outputs

string
another string

instead of expected

another string
another string

If I call af in b.py like this

a.f(a.S)

this works as expected, but is there any way to change default variable value?

The short answer is: You can't.

The reason for this is that the function default arguments are created at function definition time, and the defaults are not meant to be re-defined. The variable name is bound once to a value and that is all, you can't re-bind that name to another value. First, let's look at variables in global scope:

# create a string in global scope
a = "string"

# b is "string"
b = a

a += " new" # b is still "string", a is a new object since strings are immutable

You've now just bound a new name to "string", and "string new" is a completely new value bound to a, it does not change b because str += str returns a new str , making a and b refer to different objects.

The same happens with functions:

x = "123"

# this expression is compiled here at definition time
def a(f=x):
    print(f)

x = "222"
a()
# 123

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:

x = []

def a(f=x):
    print(x)

a()
[]

# mutate the reference to the default defined in the function
x.append(1)

a()
[1]

x
[1]

The default argument was already defined, and the name f was bound to the value [] , that cannot be changed. You can mutate the value associated with f , but you cannot bind f to a new value as a default. To further illustrate:

x = []

def a(f=x):
    f.append(1)
    print(f)

a()
x
[1]

# re-defining x simply binds a new value to the name x
x = [1,2,3]

# the default is still the same value that it was when you defined the
# function, albeit, a mutable one
a()
[1, 1]

It might be better to either A) pass the global variable in as an argument to the function or B) use the global variable as global . If you are going to change the global variable you wish to use, don't set it as a default parameter and choose a more suitable default:

# some global value
x = "some default"

# I'm choosing a default of None here
# so I can either explicitly pass something or
# check against the None singleton
def a(f=None):
    f = f if f is not None else x
    print(f)

a()
some default

x = "other default"
a()
other default

a('non default')
non default

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM