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

Python对不可变成员变量的引用,python,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

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

我有一个函数类,它只做一件事。此函数在执行过程中使用一个成员变量,使用哪个成员变量取决于输入参数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
现在我明白了为什么这段代码不能满足我的要求。因为我们使用的是不可变的int类型,所以我们的变量index指的是成员变量self.aself.b,而不是self.aself.b本身的值。函数结束时,索引表示不同的值整数,但self.aself.b不变

很明显,我的想法太像C++了。我想要一些相当于

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

如何以Pythonic的方式实现这一点?

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

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

如果不想跟踪字符串,可以使用属性代理类将其抽象出来,如下所示:

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+=1
setattr(obj,“x”,getattr(obj,“x”)+1)
frex进行比较。

有很多方法可以做到这一点--
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

避免使用属性名作为字符串的直觉通常是正确的(尽管在这种特殊情况下,这是一个很好的解决方案),避免通过字符串查找属性和变量的基本解决方案是“使用dict”。

显然,如果由于值不可变而出现问题,请使其可变!这当然是一个完整的破解,可能不符合任何“Pythonic”的定义


我希望避免使用成员的字符串id。。。我只是觉得有点马虎。这是一种python风格的编码吗?对于间接操作对象属性的特定情况,使用
getattr()
setattr()
几乎总是比其他方法更受欢迎,因为其他方法必然不那么明确。@Harry,大多数时候,避免使用
getattr
setattr
,这是谨慎的,但在这种情况下,这是相当有益的。它不会使适用的代码很难阅读或理解,也不会接受属性名称的任意值;查看我的答案。@TokenMacGuy、
getattr
setattr
比使用dict更受欢迎?请注意,这种if
if
/
elif
链通常最好用dict替换(
{do_this':self.a,'do_that':self.b}
).你们的方法不起作用和价值的不变性无关。这让我觉得过于工程化了。这是更多需要理解、调试和测试的代码,没有真正的好处。完全可能。:-)如果属性不必绑定到对象实例,那就更好了。呵呵,我也想到了这个技巧,但是是的。。。不是最漂亮的代码!谢谢:)“将其放入列表”是如何添加间接级别的常用示例,但我不确定我是否见过这样的情况,我认为这似乎是最好的解决方案。
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