我遇到了无法间接引用成员变量的问题。
我有一个具有功能的类,它可以做一件事。此函数在执行期间使用成员变量,并且它使用的成员变量取决于输入参数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方式实现这一目标?
答案 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 += 1
与setattr(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