Reputation: 1782
Why does test2()
below print "True False"? I would expect "False False".
I expect test2()
to change the global value EC
to be False, so ec
should also be False.
Why not?
Is there a straightforward way to get the "False False" behavior?
EC = True
def test1(ec=EC):
print(ec, EC)
def test2():
global EC
EC=False
test1()
Upvotes: 0
Views: 173
Reputation: 43
I think of your problem as this:
EC
, it stay in location A in your memory.test1()
, it stay in location B.test2()
, it stay in location C.Let say: in test2()
, you set EC
as global variable, it runs, but save that global EC
in location D, at the end of test2()
, EC
gets its value from D.
That means when you call test1()
inside test2()
, EC
that set to ec stay in A, not in D. But somehow when you print, it looks for D in your memory.
EC = True
def test1(ec=EC):
print(ec, EC)
def test2():
global EC
EC = False
test1(ec=EC)
This is my code, and it works with Python 3.6.9
To understand this, in Python there are 2 build-in functions are hex()
and id()
, so when you want to find where your variable stay in your memory you can check by hex(id(EC))
You can run your code as:
EC = True
print(hex(id(EC)))
def test1(ec=EC):
print(ec, EC)
print(hex(id(test1)))
def test2():
global EC
EC = False
print(hex(id(EC)))
test1()
print(hex(id(test2)))
You will find out that your global EC
& first EC
variable are stay in 2 different location. That's why you get the result of True False
Upvotes: 0
Reputation: 280181
First, that's a default value, not a keyword argument. If you want to pass keyword arguments, that would look like this:
def test1(ec):
print(ec)
test1(ec=True)
Second, unlike most languages with default argument values, Python evaluates default values at function definition time, not function call time. This is an extremely unusual design decision that causes a lot of problems. The typical workaround is to use a sentinel value like None
as the default, and compute the "real" default inside the function if the sentinel is detected:
EC = True
def test1(ec=None):
if ec is None:
ec = EC
print(ec, EC)
def test2():
global EC
EC=False
test1()
Upvotes: 1
Reputation: 155323
Function defaults bind at function definition, not at function call. For immutable types like bool
, nothing you do to EC
after test1
is defined will affect the default value bound to test1
's ec
argument.
If you want call time binding, you're stuck accepting a sentinel default, and loading dynamically in response to getting it, e.g.:
def test1(ec=None):
if ec is None:
ec = EC
...
If None
might be a valid argument (and therefore not usable as a sentinel value), you can make and use your own sentinel object, used for no other purpose, instead:
_test1_sentinel = object() # Cheapest way to make new, guaranteed unique object
def test1(ec=_test1_sentinel):
if ec is _test1_sentinel:
ec = EC
...
Upvotes: 2