Python对成员变量的引用是不可变的

时间:2011-08-31 15:41:40

标签: python

我遇到了无法间接引用成员变量的问题。

我有一个具有功能的类,它可以做一件事。此函数在执行期间使用成员变量,并且它使用的成员变量取决于输入参数cmd。这是一些代码:

class Foo(object):
    def __init__(self):
        self.a = 0
        self.b = 0

    def bar(self, cmd):
        if cmd == "do_this":
            index = self.a
        elif cmd == "do_that":
            index = self.b

        filename = "file-%d.txt" % index
        fp = open("filename", "w")

        # do some more things which depend on and *should* change
        # the value of self.a or self.b

        return

现在我理解为什么这段代码没有按我的意愿行事。因为我们使用的是immutable int类型,所以我们的变量 index 是指成员变量 self.a self.b 的值,而不是 self.a self.b 自己。在函数结束时, index 引用不同的整数值,但 self.a self.b 不变。

我显然也在想C ++ - 是的。我想要一些等同于

的东西
index = &(self.a)
filename = "file-%d.txt" % *index

我如何以Pythonic方式实现这一目标?

4 个答案:

答案 0 :(得分:3)

在这种特殊情况下,我只会跟踪您感兴趣的属性的字符串名称。例如:

class Foo(object):
    def __init__(self):
        self.a = 0
        self.b = 0

    def bar(self, cmd):
        if cmd == "do_this":
            index_name = 'a'
        elif cmd == "do_that":
            index_name = 'b'

        index = getattr(self, index_name)

        filename = "file-%d.txt" % index
        fp = open("filename", "w")

        # do some more things which depend on and *should* change
        # the value of index
        #              ^^^^^

        setattr(self, index_name, index)

        return

答案 1 :(得分:3)

有很多种方法可以做到这一点 - setattr和属性名称作为字符串,编写为每个属性设置的函数或方法等。一个相当清晰且可能方便的方法是

class Foo(object):

    def __init__(self):
        self.values = {'a': 0, 'b': 0}

    def bar(self, cmd):
        if cmd == "do_this":
            index = 'a'
        elif cmd == "do_that":
            index = 'b'

        filename = "file-%d.txt" % index
        f = open("filename", "w")

        ...

        self.values[index] = something

您避免将属性名称用作字符串的直觉通常是正确的(尽管在这种特殊情况下这很容易就是一个很好的解决方案),并且避免按字符串查找属性和变量的库存解决方案是“使用字典”。

答案 2 :(得分:0)

如果您不想跟踪字符串,可以使用属性代理类对其进行抽象,如下所示:

class AttributeProxy(object):
    def __init__(self, obj_inst, attr_name):
        self.obj_inst, self.attr_name = obj_inst, attr_name

    @property
    def value(self):
        return getattr(self.obj_inst, self.attr_name)

    @value.setter
    def value(self, value):
        setattr(self.obj_inst, self.attr_name, value)

用法:

class Test(object):
    x = 0
    y = 1

test = Test()

x = AttributeProxy(test, "x")
y = AttributeProxy(test, "y")

print x.value   # 0
x.value += 1
print x.value == y.value

当然,它仍在幕后使用getattr()setattr(),但客户端代码看起来更好一些。将x.value += 1setattr(obj, "x", getattr(obj, "x") + 1) frex进行比较。

答案 3 :(得分:0)

显然,如果您遇到问题,因为值是不可变的,请将其变为可变!这当然是一个完整的黑客,可能不符合“Pythonic”的任何定义。

class Foo(object):
    def __init__(self):
        self.a = [0]
        self.b = [0]

    def bar(self, cmd):
        if cmd == "do_this":
            index = self.a
        elif cmd == "do_that":
            index = self.b

        filename = "file-%d.txt" % index[0]
        fp = open("filename", "w")

        # do some more things which depend on and *should* change
        # the value of self.a or self.b
        index[0] = 42

        return