Álvaro F. b.f.
Álvaro F. b.f.

Reputation: 45

Two different Python classes sharing attribute with same underlying object

Is it possible in Python to have two objects, each of them an instance of a different class, that always share the same value for a particular attribute?

For instance, suppose the following code:

class A():
    def __init__(self):
        self.attrA = "attrA"
        self.grid = None

    def init_grid(self, x):
        self.grid = x

class B():
    def __init__(self):
        self.attrB = "attrB"
        self.grid = None

    def init_grid_as_preexisting(self, pre_grid):
        self.grid = pre_grid


a = A()
a.init_grid([1,2,3])

b = B()
b.init_grid_as_preexisting(a.grid)

print("a.grid, b.grid = ", a.grid, b.grid)
# OUT: a.grid, b.grid =  [1, 2, 3] [1, 2, 3]

a.grid = [4,5,6]

print("a.grid, b.grid = ", a.grid, b.grid)
# OUT: a.grid, b.grid =  [4, 5, 6] [1, 2, 3]

b.grid = [7,8,9]

print("a.grid, b.grid = ", a.grid, b.grid)
# OUT: a.grid, b.grid =  [4, 5, 6] [7, 8, 9]

Here my goal would be for a.grid and b.grid to contain the same value always, regardless of whether one is initialized from the other or which one is modified; the desired output would be then:

a.grid, b.grid =  [1, 2, 3] [1, 2, 3]
a.grid, b.grid =  [4, 5, 6] [4, 5, 6]
a.grid, b.grid =  [7, 8, 9] [7, 8, 9]

In this question it is suggested to use a base class containing a class attribute, and use a static method to modify the desired shared attribute. I would rather not use this solution as I don't want to have this attribute shared among all instances always, only when it is strictly desired. From this other question, I guess I could use the Mutable Default Argument property to have a shared value for a given parameter, but again, I don't always want the parameter to be shared.

In short, is it possible to have two objects, each an instance of two different classes, to have a shared parameter?

Upvotes: 2

Views: 1161

Answers (3)

Tom McLean
Tom McLean

Reputation: 6295

You can have a parent class to hold the data:

class GridHolder:
    def __init__(self):
        self.grid = None


class A:

    def __init__(self, grid_holder: GridHolder):
        self.attrA = "attrA"
        self.grid_holder = grid_holder

    @property
    def grid(self):
        return self.grid_holder.grid

    @grid.setter
    def grid(self, value):
        self.grid_holder.grid = value


class B:
    def __init__(self, grid_holder: GridHolder):
        self.attrB = "attrB"
        self.grid_holder = grid_holder

    @property
    def grid(self):
        return self.grid_holder.grid

    @grid.setter
    def grid(self, value):
        self.grid_holder.grid = value

data_holder = GridHolder()

a = A(data_holder)
a.grid = [1, 2, 3]

b = B(data_holder)

print("a.grid, b.grid = ", a.grid, b.grid)
# OUT: a.grid, b.grid =  [1, 2, 3] [1, 2, 3]

a.grid = [4, 5, 6]

print("a.grid, b.grid = ", a.grid, b.grid)
# OUT: a.grid, b.grid =  [4, 5, 6] [1, 2, 3]

b.grid = [7, 8, 9]

print("a.grid, b.grid = ", a.grid, b.grid)
# OUT: a.grid, b.grid =  [4, 5, 6] [7, 8, 9]

Output:

a.grid, b.grid =  [1, 2, 3] [1, 2, 3]
a.grid, b.grid =  [4, 5, 6] [4, 5, 6]
a.grid, b.grid =  [7, 8, 9] [7, 8, 9]

Upvotes: 2

Maurice Meyer
Maurice Meyer

Reputation: 18106

You could make use of a class variable and using .grid as property, A and B inherit from grid the properties only:

class grid:
    _grid = None

    @property
    def grid(self):
        return grid._grid

    @grid.setter
    def grid(self, value):
        grid._grid = value


class A(grid):
    def __init__(self):
        self.attrA = "attrA"


class B(grid):
    def __init__(self):
        self.attrB = "attrB"


a = A()
a.grid = [1, 2, 3]

b = B()
print("a.grid, b.grid = ", a.grid, b.grid)
a.grid = [4, 5, 6]
print("a.grid, b.grid = ", a.grid, b.grid)
b.grid = [7, 8, 9]
print("a.grid, b.grid = ", a.grid, b.grid)

Out:

a.grid, b.grid =  [1, 2, 3] [1, 2, 3]
a.grid, b.grid =  [4, 5, 6] [4, 5, 6]
a.grid, b.grid =  [7, 8, 9] [7, 8, 9]

Upvotes: 0

quamrana
quamrana

Reputation: 39354

You can have the B instance refer to the A instance and use properties to refer to the grid attribute:

class A():
    def __init__(self):
        self.attrA = "attrA"
        self.grid = None

    def init_grid(self, x):
        self.grid = x

class B():
    def __init__(self, a):
        self.attrB = "attrB"
        self.a = a

    @property
    def grid(self):
        return self.a.grid 

    @grid.setter
    def grid(self, value):
        self.a.grid = value

a = A()
a.init_grid([1,2,3])

b = B(a)

print("a.grid, b.grid = ", a.grid, b.grid)
# OUT: a.grid, b.grid =  [1, 2, 3] [1, 2, 3]

a.grid = [4,5,6]

print("a.grid, b.grid = ", a.grid, b.grid)
# OUT: a.grid, b.grid =  [4, 5, 6] [1, 2, 3]

b.grid = [7,8,9]

print("a.grid, b.grid = ", a.grid, b.grid)
# OUT: a.grid, b.grid =  [4, 5, 6] [7, 8, 9]

Output as requested

Upvotes: 1

Related Questions