将名称链接到另一个名称

时间:2014-06-11 16:47:40

标签: python reference

我有以下代码:

class B:

    def __init__(self, msg):
        self.msg = msg

class A:

    def __init__(self, msg):
        self.msg = msg
        self.b = B(self.msg)

    def update(self, msg):
        self.msg = msg

a = A('hello')

print a.msg
print a.b.msg

a.update('bye')

print a.msg
print a.b.msg

打印哪些:

hello
hello
bye
hello

这不是我想要的。我需要的是a.b.msg是"链接"到a.msga.b.msg必须始终引用与a.msg相同的对象,即使在重新绑定a.msg之后也是如此。这可能吗?我怎么能这样做?

3 个答案:

答案 0 :(得分:1)

您的实际问题是,您希望行为类似于C ++中的引用调用。要实现这一点,您可以做的是使用一点hack来模拟内存位置。 Found here工作的原因可以在this questions accepted answer中找到,它与Pythons可变和不可变对象有关。

class ref:
    def __init__(self, obj): self.obj = obj
    def get(self):    return self.obj
    def set(self, obj):      self.obj = obj

class B:
    def __init__(self, msg):
        self.msg = msg

class A:
    def __init__(self, msg):
        self.msg = ref(msg)
        self.b = B(self.msg)

    def update(self, msg):
        self.msg.set(msg)

a = A('hello')

print a.msg.get() #hello
print a.b.msg.get() #hello

a.update('bye')

print a.msg.get() #bye
print a.b.msg.get() #bye

但是,如果这对您的代码进行了太多更改,那么您还可以做的是在每个函数中使用msg(self)定义方法msg,将msg重命名为{{1} }} 管他呢。 这样,您可以通过调用message来获取String,这表示对现有代码的更改较少。但我担心如果不对代码进行任何更改,就无法解决问题。

示例二,使用a.msg()方法:

msg()

我看到的第三个解决方案是使用class B: def __init__(self, msg): self.message = msg def msg(self): return self.message.get() class A: def __init__(self, msg): self.message = ref(msg) self.b = B(self.message) def update(self, msg): self.message.set(msg) def msg(self): return self.message.get() a = A('hello') print a.msg() #hello print a.b.msg() #hello 而不是引用类:

List

一般情况下,您可以使用任何其他可变对象来实现此目的,但要注意不要重新分配某些"子类中的可变对象"就像你的例子中的class B: def __init__(self, msg): self.msg = msg class A: def __init__(self, msg): self.msg = [msg] self.b = B(self.msg) def update(self, msg): self.msg[0] = msg a = A('hello') print a.msg[0] #hello print a.b.msg[0] #hello a.update('bye') print a.msg[0] #bye print a.b.msg[0] #bye 一样。

答案 1 :(得分:1)

为什么不能b跟踪a并使用a.msg来获取msg

class MockA:
    def __init__(self, msg):
        self.msg = msg

class B:

    def __init__(self, a):
        if isinstance(a, A):
            self._a = a
        else:
            self._a = MockA(a)

    @property
    def msg(self):
        return self._a.msg

class A:

    def __init__(self, msg):
        self.msg = msg
        self.b = B(self)

    def update(self, msg):
        self.msg = msg

a = A('hello')

print a.msg
print a.b.msg

a.update('bye')

print a.msg
print a.b.msg

b = B('here')

print b.msg

打印:

hello
hello
bye
bye
here

答案 2 :(得分:0)

您可以使用属性:

class A(object):
  def __init__(self, msg):
    self.b = B(msg)

  @property
  def msg(self):
    return self.b.msg

  @property.setter
  def msg(self, value):
    self.b.msg = value

与你想要的相比,我有一点倒退。在这里,我总是将a.msg链接到a.b.msg而不是相反,但在这一点上它实际上主要是语义。这些变化似乎应该向两个方向传播,因此应该没有什么实际差异。