通过引用更改类属性

时间:2017-05-18 11:48:15

标签: python attributes mutable

我对Python比较陌生,并且存在不可变变量的问题。

我正在尝试更改类属性的值(例如car.color)。困难在于,我不能使用汽车的命名空间来做这件事。

到目前为止,我没有找到令人满意的答案。在下面的代码中,我试图总结我发现的可能解决方案(workarrounds)及其缺点:

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

实际上,函数setattr()在内部完全按照我的意愿行事。但它适用于字符串参数。 我试着研究这个函数,但它似乎是用C ++编写的。

所以我必须使用C ++来解决这个问题吗? 或者有一种Pythionic方式吗?

1 个答案:

答案 0 :(得分:5)

问题是您正在尝试从类外部重新定义实例的值。由于在__init__中您使用self定义变量,因此它们仅适用于该实例。这是一个类的重点 - 它是使它们可扩展和可重用的原因。

理想情况下,您可以在类中创建一个方法来更新这些属性,但是,如果您确实需要从外部函数更新类,则必须将其定义为类级别变量。例如:

class Car:

    def __init__(self):
        Car.color = "green"
现在可以使用

更新

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

在课外,因为您尚未将其分配给一个特定实例。然而,这样做会带来问题。由于我们没有单独的实例变量,如果我们尝试重新实例化该类,我们就会陷入先前改变的状态,即 如果名称 ==“主要”:

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

这就是为什么类本身应该是自包含的并且意图是不可变的 - 实例本身应该被更改。