benpay benpay - 27 days ago 20
Python Question

Confusion about global and immutable

I'm so confused with

global
and immutable variable. I have this code:

class ProcessObject:
RR = 0
def b(self):
self.RR=5
print("valor: ", self.RR)

def c(self):
print("final: ", self.RR)

def d(self):
global RR
RR = 3
print("valor: ", RR)

print(RR)

proce = ProcessObject()
proce.b()
proce.c()
proce.d()
proce.c()


And it have this output:

0
value: 5
final: 5
value: 3
final: 5


But I not understand why with "
c
" the value is 5 if the RR is an object immutable. And why "
d
" using global no mute the value of
RR
.

Answer

This has nothing to do with immutability... But anyway:

class ProcessObject:
    # this "RR" lives in the `class` statement namespace, 
    # it's accessible as 'RR' in this namespace. After the
    # `class` statement is executed, it becomes an attribute
    # of the `ProcessObject` class, accessible as `ProcessObject.RR`,
    # and thru instances as `ProcessObject().RR`. 
    #  
    RR = 0

    def b(self):
        # this creates an "RR" instance attribute
        # on the current instance (`self`), which shadows
        # the "RR" class attribute
        self.RR=5
        print("valor: ", self.RR)

    def c(self):
        print("final: ", self.RR)

    def d(self):
        # The two following lines creates a module-global
        # name "RR", which is distinct from the two previous
        # ones.  
        global RR
        RR = 3
        print("valor: ", RR)

    # this prints the value of the `RR` living in the class
    # statement scope - NOT the value of the yet non-existing
    # global RR
    print(RR)

proce = ProcessObject()
proce.b() # this creates the `proce.RR` instance attribute
proce.c()
proce.d()
proce.c()

But I not understand why with "c" the value is 5 if the RR is an object immutable.

It prints '5' because you assigned that value to proce.RR when calling proce.b(). You're confusing names and values... RR is not an object, it's a name which is bound to an object. The fact that it's at one point bound to an immutable object doesn't mean you cannot rebind it to another object (mutable or not, that's irrelevant here).

And why "d" using global no mute the value of RR

And here you are confusing binding (assignment) and mutating. binding (assignment) means "make that name points to this object", mutating means "change the state of this object". An example of mutation is adding or removing an element to/from a list, or reversing a list in place.

FWIW, the call to proce.d DO rebind (and actually bind on the first call) the module-global "RR".

You may want to run this '"extended" version of your script to find out what really happens:

print("before : globals = {}".format(globals()))

class ProcessObject:
    RR = 0
    print "RR defined in the class namespace - not in globals: {}".format(globals())

    def __init__(self):
        print("in init")
        print("   self.__dict__ : {}".format(self.__dict__))
        print("   ProcessObject.__dict__ : {}".format(ProcessObject.__dict__))



    def b(self):
        print("before calling b - self.__dict__ : {}".format(self.__dict__))
        self.RR=5
        print("valor: ", self.RR)
        print("after calling b - self.__dict__ : {}".format(self.__dict__))

    def c(self):
        print("before calling c - self.__dict__ : {}".format(self.__dict__))
        print("final: ", self.RR)

    def d(self):
        print("before calling d : globals = {}".format(globals()))
        global RR
        RR = 3
        print("valor: ", RR)
        print("after calling d : globals = {}".format(globals()))

    print(RR)

print("after class statement: globals : {}".format(globals()))



proce = ProcessObject()
proce.c()
proce.b()
proce.c()
proce.d()
proce.c()
Comments