Python Forum
Variable scope - "global x" didn't work...
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Variable scope - "global x" didn't work...
#1
I am struggling to understand updating a 'global' dictionary (i.e., it's defined in the main module and I want to update it in a subroutine). I understand that I need to do something since dict_1 in the mainline isn't what would be updated in a function. So I tried this experiment:

dict_1 = {}
dict_2 = {}

def upd_dict1(dict_1_copy):
    print("sub dict_1_copy a is " + str(dict_1_copy["a"]))
    dict_1_copy["a"] = 100
    print("sub dict_1_copy a is " + str(dict_1_copy["a"]))
    return dict_1_copy

if __name__ == "__main__":
    dict_1["a"] = 1
    dict_1["b"] = 2
    dict_2["a"] = 0
    dict_2["b"] = 22
    print("dict_1 a is " + str(dict_1["a"]) + " b4 upd - sb 1")
    print("dict_1 b is " + str(dict_1["b"]) + " b4 upd - sb 2")
    print("dict_2 a is " + str(dict_2["a"]) + " b4 upd - sb 0")
    print("dict_2 b is " + str(dict_2["b"]) + " b4 upd - sb 22\n")
    dict_2 = upd_dict1(dict_1)
    print("dict_1 a is " + str(dict_1["a"]) + " aft upd - sb 1")
    print("dict_1 b is " + str(dict_1["b"]) + " aft upd - sb 2")
    print("dict_2 a is " + str(dict_2["a"]) + " aft upd - sb 100")
    print("dict_2 b is " + str(dict_2["b"]) + " aft upd - sb 2\n")
    dict_1 = dict_2
    print("dict_1 a is " + str(dict_1["a"]) + " aft copy - sb 100")
    print("dict_1 b is " + str(dict_1["b"]) + " aft copy - sb 2")
    print("dict_2 a is " + str(dict_2["a"]) + " aft copy - sb 100")
    print("dict_2 b is " + str(dict_2["b"]) + " aft copy - sb 2")
Which *should* give the results shown as "sb X" in the print statements. But what I get is

Output:
dict_1 a is 1 b4 upd - sb 1 dict_1 b is 2 b4 upd - sb 2 dict_2 a is 0 b4 upd - sb 0 dict_2 b is 22 b4 upd - sb 22 sub dict_1_copy a is 1 sub dict_1_copy a is 100 dict_1 a is 100 aft upd - sb 1 <-- THIS dict_1 b is 2 aft upd - sb 2 dict_2 a is 100 aft upd - sb 100 dict_2 b is 2 aft upd - sb 2 dict_1 a is 100 aft copy - sb 100 dict_1 b is 2 aft copy - sb 2 dict_2 a is 100 aft copy - sb 100 dict_2 b is 2 aft copy - sb 2
I completely do not understand why the line marked THIS get what it gets.

Can anyone tell me what I'm missing here?

Paul
Reply
#2
You call it a copy, but there are no copies made anywhere. When you pass an object to a function, if that object is mutable the function can modify it.

Here you pass dict1 to upd_dict1 on line 19. This function both modifies the object that is passed in, and returns another reference to that object.

Before line 19 you have two dictionaries: dict_1 and dict_2. After line 19, both variables point at the same object (the original dict_2 is discarded). Line 24 doesn't do anything because they are already the same. You can add a statement like:

print(f"dict_1 and dict_2 are the same object: {dict_1 is dict_2}"
Reply
#3
Normally you do not need to use "global" with dictionaries and lists. "global" controls how assignment is done. In the code below the "global x" in set_global_x() tells Python that the assignment "x = value" should not create a new x variable in the function scope. The same assignment in set_local_x() creates "x" inside the set_local_x namespace. Setting this x does not change the value of the "global" x.
x = 1

def set_global_x(value):
    global x
    x = value

def set_local_x(value):
    x = value

def print_x():
    print('x =', x)

print_x()
set_global_x(2)
print_x()
set_local_x(3)
print_x()
Output:
x = 1 x = 2 x = 2
When using a mutable object like a dictionary or list you don't need to use global if all you want to do is change something in the mutable object.
x = [1]

def set_global_x(value):
    global x
    x[0] = value

def set_local_x(value):
    x[0] = value

def print_x():
    print('x =', x[0])

print_x()
set_global_x(2)
print_x()
set_local_x(3)
print_x()
Output:
x = 1 x = 2 x = 3
Reply
#4
(Dec-24-2020, 08:13 PM)bowlofred Wrote: You call it a copy, but there are no copies made anywhere. When you pass an object to a function, if that object is mutable the function can modify it.

Here you pass dict1 to upd_dict1 on line 19. This function both modifies the object that is passed in, and returns another reference to that object.

Before line 19 you have two dictionaries: dict_1 and dict_2. After line 19, both variables point at the same object (the original dict_2 is discarded). Line 24 doesn't do anything because they are already the same. You can add a statement like:

print(f"dict_1 and dict_2 are the same object: {dict_1 is dict_2}"

Thank you. The thing I am trying to fix is that when I do this in a third-level function:

for curr_id in dict_1: # loop through the dictionary
# code code code
    dict_1[curr_id].incl_ips.append(ipaddress.ip_network(rng_chop[0] + "/" + str(myprefix), False))
# code code code
it appends the value in the loop iteration to THE SAME dictionary entry.

Also, from my OP, essentially dict_1_copy is discarded when I exit the function and recreated the next time the function is called?
Reply
#5
(Dec-25-2020, 12:00 AM)ptrivino Wrote: Thank you. The thing I am trying to fix is that when I do this in a third-level function:

for curr_id in dict_1: # loop through the dictionary
# code code code
    dict_1[curr_id].incl_ips.append(ipaddress.ip_network(rng_chop[0] + "/" + str(myprefix), False))
# code code code
it appends the value in the loop iteration to THE SAME dictionary entry.

I'm not sure I follow this part. What are you expecting it to append to?

Quote:Also, from my OP, essentially dict_1_copy is discarded when I exit the function and recreated the next time the function is called?

Yes. I wouldn't use "discarded" here because the actual data remains (since it has another name outside the function). I would say it is "reassigned" the next time the function is called. No data is created at that time.
Reply
#6
(Dec-25-2020, 12:44 AM)bowlofred Wrote:
(Dec-25-2020, 12:00 AM)ptrivino Wrote: Thank you. The thing I am trying to fix is that when I do this in a third-level function:

for curr_id in dict_1: # loop through the dictionary
# code code code
    dict_1[curr_id].incl_ips.append(ipaddress.ip_network(rng_chop[0] + "/" + str(myprefix), False))
# code code code
it appends the value in the loop iteration to THE SAME dictionary entry.

I'm not sure I follow this part. What are you expecting it to append to?

Quote:Also, from my OP, essentially dict_1_copy is discarded when I exit the function and recreated the next time the function is called?

Yes. I wouldn't use "discarded" here because the actual data remains (since it has another name outside the function). I would say it is "reassigned" the next time the function is called. No data is created at that time.

In the dict_1 entries I set the value to an object/class with 4 attributes (incl_ips is one of them), each a list of other values. But what doesn't work is that, in each loop through with a new curr_id, the SAME dictionary entry (or possibly ALL entries, I've seen that in another try)is updated/appended to.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Getting a GET request output text into a variable to work with it. LeoT 2 523 Feb-24-2021, 02:05 PM
Last Post: LeoT
  DataFrame operations didn't change orginal HoldYourBreath 5 648 Jan-10-2021, 02:01 PM
Last Post: jefsummers
  Python Closures and Scope muzikman 2 557 Dec-14-2020, 11:21 PM
Last Post: muzikman
  Spyder Quirk? global variable does not increment when function called in console rrace001 1 516 Sep-18-2020, 02:50 PM
Last Post: deanhystad
  NameError for global variable leviporton 3 868 Jul-10-2020, 06:51 PM
Last Post: bowlofred
  Block of code, scope of variables and surprising exception arbiel 8 1,291 Apr-06-2020, 07:57 PM
Last Post: arbiel
  Function Recognises Variable Without Arguments Or Global Variable Calling. OJGeorge4 1 790 Apr-06-2020, 09:14 AM
Last Post: bowlofred
  Global Variable Not Updating joew 2 3,969 Jan-26-2020, 04:15 PM
Last Post: joew
  Help with Global/Coerced Variable (Understanding Scope) Rev2k 6 1,371 Jan-09-2020, 03:43 AM
Last Post: Rev2k
  Solving a scope issue profconn1 4 1,080 Nov-01-2019, 07:46 PM
Last Post: profconn1

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020