1

As a follow up to this question

Why can I change the global value of x.a within def A? I am guessing it has to do with the fact that it is a class since it would not work with a regular variable because it would be redefined in the local scope of def A, but I am not quite understanding what is happening.

Case 1

class X:    
    def __init__(self):
        self.a = 1
        self.b = 2
        self.c = 3

class Y:        
    def A(self):        
        print(x.a,x.b,x.c)
        x.a = 4           

x = X()
y = Y()
y.A()

print(x.a,x.b,x.c)
Community
  • 1
  • 1
Isopycnal Oscillation
  • 3,234
  • 6
  • 21
  • 37

3 Answers3

0

Global names can be read within functions:

x = 5
def read_x():
    print(x)

Globals that reference mutable types can also be mutated within functions:

x = [1, 2, 3]
def mutate_x():
    x[0] = 'One'

What you can't do to a global within the scope of a function is assignment:

x = 5
def set_x():
    # this simply assigns a variable named x local to this function -- it doesn't modify the global x
    x = 3
# now, back outside the scope of set_x, x remains 5
print(x)
5

Unless you explicitly declare the global within the scope of the function:

x = 5
def set_x():
    global x
    x = 3
# back outside the function's scope
print(x)
3

What you're doing in your example is "mutating" -- modifying an attribute of an object. Assigning a value to an attribute of a user-defined type is one example of mutation, just like modifying an element of a list or a dictionary. That's why this works.

grayshirt
  • 615
  • 4
  • 13
0

If you set x = Y() in A scope it would create a local x in that scope. In this case however, you are not setting x, you are setting x.a. Looking up variables takes into account global variables too. Imagine you are doing this instead setattr(x, "a", 4) and it will make more sense.

Also if I remember correctly you can "import" global variables into a function scope by using the global keyword. (see Use of "global" keyword in Python)

Community
  • 1
  • 1
OdraEncoded
  • 3,064
  • 3
  • 20
  • 31
0

The class A doesn't have an init method that defines x, so the method A, when you try to access the attribute a of x, try to find the x object in the local scope, and since it can't find it then it looks the outside scope where an object name x is present, it grabs that object and override the attribute a.

So basically what you are doing is modify the actual attribute a of the object x that you create before you call y.A().

It's the very basic foundation of a closure: access a variable that is defined outside the local scope.

Mauro De Giorgi
  • 394
  • 2
  • 11