Home > Enterprise >  namespace dictionary confusion
namespace dictionary confusion

Time:06-17

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

  • Related