Unable to access modified value of imported variable
Question: I am new to python and have some problem understanding the scope here.

I have a python module A with three global variables :

    
    
    XYZ = "val1"
    ABC = {"k1" : "v1", "k2" : "v2"}
    PQR = 1
    
    class Cls_A() :
        def sm_fn_A(self) :
            global XYZ
            global ABC
            global PQR
    
            XYZ = "val2"
            ABC["k1"] = "z1"
            ABC["k3"] = "v3"
            PQR += 1
    

And another module B :

    
    
    from A import Cls_A, XYZ, ABC, PQR
    
    class Cls_B():
        def sm_fn_B(self) :
            Cls_A().sm_fn_A()
            print XYZ
            print ABC
            print PQR
    
    Cls_B().sm_fn_B()
    

This gives me the following output :

    
    
    val1
    {'k3': 'v3', 'k2': 'v2', 'k1': 'z1'}
    1
    

Since these are all global variables, why do I not get updated values of all
the global variables printed ?


Answer: # Explanation

Three global variables are defined in module `A`, in this code:

    
    
    XYZ = "val1"
    ABC = {"k1" : "v1", "k2" : "v2"}
    PQR = 1
    

Then new global variables `XYZ`, `ABC`, `PQR` are defined in module `B`, in
this code:

    
    
    from A import Cls_A, XYZ, ABC, PQR
    

This line of code creates new variables, just as if the following was written:

    
    
    import A
    XYZ = A.XYZ
    ABC = A.ABC
    PQR = A.PQR
    

It is important to understand that `A.XYZ` and `B.XYZ` are two variables which
point to the same object. They are not the same variable.

Then a new object is assigned to `A.XYZ`:

    
    
        XYZ = "val2"
    

This modified `A.XYZ`, but did not modify `B.XYZ`. The two used to be two
variables which pointed to the same object, but now `A.XYZ` points to a
different object.

On the other hand, `A.ABC` is not assiciated with a different object. Instead,
the object itself is modified. When the object is modified, both `A.ABC` and
`B.ABC` still point to the same object:

    
    
        ABC["k1"] = "z1"
        ABC["k3"] = "v3"
    

The third case is also not a case of object modification, but rather
reassignment:

    
    
        PQR += 1
    

The value was incremented. That created a new object and than thet new object
was assigned to `A.PQR`. `B.PQR` is unchanged. This is equivalent to:

    
    
        PQR = PQR + 1
    

A thing which may not be obvious is that both strings and integers are
_immutable_ objects in Python (there is no way to change number to `2` to
become `3` \- one can only assign a different int object to a variable, not
change the existing one). Because of that, there is actually no way to change
`A.XYZ` in a way that affects `B.XYZ`.

## The dictionary could behave the same way

The reason why with the dictionary it _"worked"_ is that the object was
modified. If a new dictioanry was assigned to `A.ABC`, that would not work.
E.g.

    
    
        ABC = {'k3': 'v3', 'k2': 'v2', 'k1': 'z1'}
    

Now it would not affect `B.ABC`, because the object in `A.ABC` was not
changed. Another object was assigned to `A.ABC` instead.

# Not related to modules

The same behaviour can be seen without any modules:

    
    
    A_XYZ = "val1"
    A_ABC = {"k1" : "v1", "k2" : "v2"}
    A_PQR = 1
    
    B_XYZ = A_XYZ
    B_ABC = A_ABC
    B_PQR = A_PQR
    
    A_XYZ = "val2"
    A_ABC["k1"] = "z1"
    A_ABC["k3"] = "v3"
    A_PQR += 1
    
    print B_XYZ
    print B_ABC
    print B_PQR
    

Prints:

    
    
    val1
    {'k3': 'v3', 'k2': 'v2', 'k1': 'z1'}
    1
    

# Solution

Well, don't keep reference to the temporary object. Use the variable which has
the correct value.

For example, in module `B`:

    
    
    import A
    
    class Cls_B():
        def sm_fn_B(self) :
            A.Cls_A().sm_fn_A()
            print A.XYZ
            print A.ABC
            print A.PQR
    
    Cls_B().sm_fn_B()
    

Now there is actually no `B.XYZ` variable, which could be wrong. `A.XYZ` is
always used.

