I'm trying to understand why one of these fails and the other works.
my_prd = { 'server': 'prd.my.company.com' }
my_lab = { 'server': 'prd.my.company.com' }
my_srv = {}
def test_fails(which):
if which == 'prd':
my_srv = my_prd
else:
my_srv = my_lab
def test_works(which):
if which == 'prd':
my_srv['server'] = my_prd['server']
else:
my_srv['server'] = my_lab['server']
Output:
fails: my_srv={}
works: my_srv={'server': 'prd.my.company.com'}
I'm going to move my reference logic outside of my function to deal with this, but I'd like to understand why my_srv
is in scope enough that I can assign values to it but not in scope enough to be referenced or copy()
ied?
CodePudding user response:
In test_fails()
, you assign my_srv = my_prd
(or my_srv = my_lab
). This means that my_srv
is a variable referring to my_prd
, like what we call a "pointer" in other languages (in Python, "everything is a pointer"). You can use my_srv
for the rest of test_fails()
, but once you leave the function that local variable is forgotten and my_srv
refers once more to the empty dictionary.
Maybe this will help with what you were hoping to do:
>>> my_prd = { 'server': 'prd.my.company.com' }
>>> my_lab = { 'server': 'prd.my.company.com' }
>>> my_srv = {}
>>> def test_fails(which):
... if which == 'prd':
... my_srv = my_prd
... else:
... my_srv = my_lab
... my_srv["key"] = "item"
...
>>> print(my_prd)
{'server': 'prd.my.company.com'}
>>> test_fails("prd")
>>> print(my_prd)
{'server': 'prd.my.company.com', 'key': 'item'}
CodePudding user response:
When you create a variable inside a function, that variable is local by default, which means it ceases to exist as soon as you exit the function (and is not stored in the same place as global variables, so having a global and a local variable with the same name is not an issue), that's what you did by writing
my_srv = my_prd
when you exit test_fails() and access my_srv, python goes looking for my_srv in the global variables, which it finds untouched and equal to {}, the global my_srv and the local my_srv were never related, they just happened to have the same name but always resided in two distinct environments.
In test_works() however, you don't create any variable, you tell python to create an extra key/value pair in a dictionary that already exists, the my_srv global variable, therefore when you exit test_works() your work is still there.
CodePudding user response:
As others have mentioned, Python creates local variables by default. Looks like in Python 3.x at least that there are some keywords like global and nonlocal that can alter how the namespace is handled.
In my case, this works:
def test_fails(which):
global my_srv #<<< Add this and it will work
if which == 'prd':
my_srv = my_prd
else:
my_srv = my_lab
A good reference I found is: Global vs. Local Variables and Namespaces