0

I have created two class A and B (use @property to get and set their attribute). class B has a member whose type is class A. How to set the attribute of b.a.x?

class A:

class A(object):
    def __init__(self, x=0, y=0):
        self._x = x
        self._y = y

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @property
    def y(self):
        return self._y

    @y.setter
    def y(self, value):
        self._y = value

class B:

class B(object):
    def __init__(self):
        self._a = A()

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

    @a.setter
    def a(self, value):
        if isinstance(value, A):
            self._a = deepcopy(value)
        elif isinstance(value, tuple):
            self._a = A(value[0], value[1])
        elif isinstance(value, int):
            # ?           
            pass
b = B()
b.a.x = 1 # How to implementate this ?

Am I wrong with the using of @property?

rivergold
  • 7
  • 1
  • 3
  • What you have is a perfectly fine way to do it. – rsiemens May 08 '19 at 02:45
  • Did you try `b.a.x = 1`? – wwii May 08 '19 at 02:46
  • you may find useful information in this question https://stackoverflow.com/questions/42763283/access-superclass-property-setter-in-subclass – recnac May 08 '19 at 02:48
  • @rsiemens What confuses me is that `@a.setter` do not know to call `self._a.x=value` or `self._a.y=value` when an `int` value come in. Should I add `__setitem__` in both class? – rivergold May 08 '19 at 03:21
  • `b.a.x = 1` calls the getter for `B.a`; this returns an instance of `A`, so the setter for `A.x` is then called. No setter on `B` is involved. – jasonharper May 08 '19 at 03:56

2 Answers2

0

Your code works fine but if you are looking for another approach you could inherit the A class and b.a.x becomes b.x.

You can achieve this by adding the following line in B's constructor

super(A, self).__init__()

hence b.a.x == b.x

SuperCode
  • 583
  • 7
  • 21
0

adding print() to your classes shows the behaviour, calling b.a.x = 1 will make x.setter in A class in charge not a.setter in B class

example:

class A(object)
    .
    .
    @x.setter
    def x(self, value):
        print('x.setter acting')
        self._x = value


class B(object):
    .
    .
    @a.setter
    def a(self, value):
        print('a.setter acting')  # adding print 
        if isinstance(value, A):
            self._a = deepcopy(value)
        elif isinstance(value, tuple):
            self._a = A(value[0], value[1])
        elif isinstance(value, int):
            # ?           
            pass

b = B()
b.a.x = 1 # x.setter will be in charge not a.setter

output:

x.setter acting

if you want a.setter to be in charge you can:

class B(object):
        .
        .
        @a.setter
        def a(self, value):
            print('a.setter acting')  # adding print 
            if isinstance(value, A):
                self._a = deepcopy(value)
            elif isinstance(value, tuple):
                self._a = A(value[0], value[1])
            elif isinstance(value, int):
                # ?           
                self._a.x = value

b = B()
b.a = 1 # a.setter will be in charge

output:

a.setter acting
Mahmoud Elshahat
  • 1,873
  • 10
  • 24