Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing class attributes by reference

I'm relatively new to Python and have problems with immutable variables.

I'm trying to change the value of a class attribute (e.g. car.color). The difficulty is, that I can not use the namespace of car for doing this.

Up to now I did not find a satisvying answer to my questions. In the code below I tried to summarize the possible solutions (workarrounds) I found and their disadvantages:

class Car:

    def __init__(self):
        self.color = "green"
        self.color_list = ["green"]
        self.color_attrib = "green"
        self.name = "VW Golf"
        """
        and many more attributes...
        """

    def makesetter(self, attribute):
        def set_value(value):
            attribute=value
        return set_value

    def set_color(self, value):
        "in this function I directly have access to car.color and can change its value: "
        self.color = value

    def set_attrib(self, attribute_string, value):
        setattr(self,attribute_string,value)

def change_attribute(attribute, value):
    "In this function I can not access car.color directly"
    attribute=value

def change_attribute_list(attribute, value):
    "In this function I can not access car.color directly"
    attribute[0] = value



if __name__ == "__main__":

    car1 = Car()

    change_attribute(car1.color, "red")
    print(car1.color)  # Color does not change because car1.color is immutable

    g = car1.makesetter(car1.color)
    g("red")
    print(car1.color)   # Color does not change because car1.color is immutable

    change_attribute_list(car1.color_list, "red")
    print(car1.color_list)  # Color changes but seems like a workarround
    # Disadvantage: in the namespace of car1, the user has to use a list to access a string value "car1.color_list[0]"

    car1.set_color("red")
    print(car1.color)  # Color changes but seems like a workarround
    # Disadvantage: Car needs a setter function for each attribute

    car1.set_attrib("color_attrib","red")
    print(car1.color_attrib)  # Color changes but seems like a workarround
    # Disadvantage: Attribute has to be passed as string & no auto completion while coding

Actually the function setattr() is internally exactly doing what I want. But it works with a string argument. I tried to look into this function but it seems to be written in C++.

So do I have to use C++ to solve this problem without a workarround? Or is there a Pythionic way of doing this?

like image 446
Jan Avatar asked May 18 '17 11:05

Jan


People also ask

Can class attributes be changed?

But be careful, if you want to change a class attribute, you have to do it with the notation ClassName. AttributeName. Otherwise, you will create a new instance variable.

How do you modify attributes in Python?

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.

How do you change the attributes of an object?

On the Custom Object Type List page, click the name of the object you want to edit. Click the Attribute Definitions tab. Click the [attribute name] or the Edit button to edit the attribute. On the Attribute Definition Details page, edit the attributes and click Apply to save your changes.


1 Answers

The problem is you are trying to redefine the value of an instance from outside of the class. Since in __init__ you are defining your variables with self, they are only available for that instance. This is the point of a class - it's what makes them extensible and reusable.

Ideally, you would make a method within the class that would update those attributes, however, if you really need to update the class from an external function, you will have to define it as a class level variable. For instance:

class Car:

    def __init__(self):
        Car.color = "green"

can now be updated using:

def change_attribute(attribute, value):
    "In this function I can not access car.color directly"
    Car.color=value

outside of the class because you have not assigned it to one specific instance. Doing this presents a problem, however. Since we don't have a separate instance variable, if we try to re-instantiate the class, we are stuck with what was previously changed, i.e. if name == "main":

car1 = Car()
car2 = Car()
change_attribute(car1.color, "red")
print(car1.color)  # Prints red
print(car2.color)  # Prints red

change_attribute(car2.color, "blue")
print(car1.color)  # Prints blue
print(car2.color)  # Prints blue

This is why classes themselves should be self contained and are meant to be immutable - the instance itself should be changed.

like image 130
Mogarrr Avatar answered Oct 08 '22 18:10

Mogarrr