NetworkingGuru
NetworkingGuru

Reputation: 35

Modifying the attribute of an object using a class method in python

I am trying to use a method defined in a class to later modify an attribute of an object made from that class, but there appears to be a scope problem that is not obvious to me. Take the following code:

class Test:
    def __init__(self, attribute):
        self.attribute = attribute
    def change_attrib(self, attribute, value):
        if attribute + value < 0: attribute = 0
        else: 
            attribute += value
            print(str(attribute) + ' This is inside the method')

test1 = Test(10)

print(str(test1.attribute) + " This is before running the method")

test1.change_attrib(test1.attribute, 10)

print(str(test1.attribute) + " This is after running the method")

test1.attribute += 20

print(str(test1.attribute) + " This is after modifying the attribute directly")

Running this code produces the following result:

10 This is before running the method
20 This is inside the method
10 This is after running the method
30 This is after modifying the attribute directly

So it appears that even though I am explicitly referring to the instance that I want to change when calling the method, everything that happens in the method, stays in the method.

I can see that modifying the attribute directly works, but I would like a guard against negative values (hence the method). I also know I can use the built-in setattr() function within the method, and that works as well, but requires that I change the syntax for the attribute to a string before passing it into the method, and I much prefer explicitly referring to the attribute. Finally, I'd really just like to understand what is going on here.

EDIT: This is the working code, based on the hint from rdvdev2. I just needed to reference self to set the instance's value:

class Test:
def __init__(self, attribute):
    self.attribute = attribute
def change_attrib(self, attribute, value):
    if attribute + value < 0: attribute = 0
    else: 
        attribute += value
        self.attribute = attribute
        print(str(attribute) + ' This is inside the method')

Also thanks to kindall for the great explanation of what was happening.

And a final expansion: The code above actually only works if the attribute is named attribute. I think kindall had the better grasp of what I needed here; in order for the function to be used to modify any attribute of the object, I need some way to reference the needed attribute. Since python appears to be passing a value instead of a reference, I have to get the reference somehow, and the least impactful way to my existing code appears to be using get/setattr....so I broke out regex and changed 160+ references.

Upvotes: 2

Views: 8131

Answers (2)

kindall
kindall

Reputation: 184191

When you pass in test1.attribute to change_attrib(), the value of attribute inside the method is not a pointer to test1.attribute that can be used to change its value. It is the integer 10. You then add the parameter value to attribute, yielding attribute equal to 20. Then the method ends and the value of attribute goes away. The value of test1.attribute never changed because you never changed it.

If you want your method to modify any attribute, you can pass its name as a string. You can then use getattr() and setattr() to get and set the attribute.

def change_attrib(self, name, value):
        attribute = getattr(self, name)
        if attribute + value < 0: attribute = 0
        else: 
            attribute += value
            print(str(attribute) + ' This is inside the method')
        setattr(self, name, attribute)

test1.change_attrib("attribute", 10)

Upvotes: 2

rdvdev2
rdvdev2

Reputation: 11

In the class method you are modifying the attribute variable, wich is a function argument. If you want to modify the object attribute you have to access self.attribute

Upvotes: 0

Related Questions