anon01
anon01

Reputation: 11181

sync attributes between objects of different type

I have two objects from different classes. What is a reasonable design choice to make the attribute of one reflect changes in the other? A naive solution that doesn't work is shown below and hopefully illustrates the aim:

Specifically:

class A(object):
     def __init__(self):
         self.x = 'a original string'

class B(object):
     def __init__(self):
         self.x = 'b original string'

a = A()
b = B()

b.x = a.x
a.x = 'a modified string'

print('b.x = "{}" was not modified when a.x = "{}" was changed'.format(b.x, a.x))

Upvotes: 0

Views: 306

Answers (1)

abarnert
abarnert

Reputation: 365975

What you're really asking for is a way to make b.x into some kind of reference to the variable a.x, and that doesn't make sense the way Python variables work—variables aren't values in Python, they're just names.

And usually, none of them is appropriate, and the answer is that the reasonable design choice is to not do this in the first place.

But when you need to, there are ways you can simulate this. Which one—if any—is appropriate depends on what you're really trying to do; for a toy example, none of them makes much sense. So I'll just show a couple.


The most obvious way is to explicitly hold onto a and the name 'x':

class B:
    def __init__(self):
        self._x = 'b original string'
        self._a = None
    def set_a(self, a):
        self._a = a
    @property
    def x(self):
        if self._a is None:
            return self._x
        else:
            return self.a.x

a = A()
b = B()

b.set_a(a)
a.x = 'a modified string'

print('b.x = "{}" was modified when a.x = "{}" was changed'.format(b.x, a.x))

Or you can replace the string with a "mutable holder"—the simplest option is a single-element list—and then you can mutate the holder that the name is bound to, instead of rebinding the name to something different:

class A(object):
     def __init__(self):
         self.x = ['a original string']

class B(object):
     def __init__(self):
         self.x = ['b original string']

a = A()
b = B()

b.x = a.x
a.x[0] = 'a modified string'

print('b.x[0] = "{}" was modified when a.x[0] = "{}" was changed'.format(b.x[0], a.x[0]))

Or you could combine the two and then try to hide the implementation from your users, but this is as misleading as it is ugly.

Upvotes: 1

Related Questions