Mongha
Mongha

Reputation: 3

AttributeError: can't set attribute error occurred when init subclass

I wrote below code with python 3.6.

class A:
    def __init__(self, p1, p2):
        self.p1 = p1
        self.p2 = p2

    @property
    def p1(self):
        return self._p1
    @p1.setter
    def p1(self, p1):
        self._p1 = p1

    @property
    def p2(self):
        return self._p2
    @p2.setter
    def p2(self, p2):
        self._p2 = p2

class B(A):
    def __init__(self, p1, p2, p3):
        super(B, self).__init__(p1, p2)
        self.p3 = p3

    @property
    def p1(self):
        return self._p1 if self.p3 is None else self._p1+1

    @property
    def p3(self):
        return self._p3
    @p3.setter
    def p3(self, p3):
        self._p3 = p3

b1 = B(1,2,3)

When create instance with class B 'AttributeError: can't set attribute' occurred. How do I fix it?

Upvotes: 0

Views: 5627

Answers (3)

chepner
chepner

Reputation: 532043

The problem is that in B, you've overriden the entire property p1, not just the getter of A's property by the same name. You need to provide the setter explicitly.

class B(A):
    ...

    # Not sure if there is a better method than
    # simply copying this from A. (At least,
    # not without creating your own custom property
    # descriptor that supports inheritance.)
    @p1.setter
    def p1(self, x):
        self._p1 = x

Upvotes: 2

Hai Vu
Hai Vu

Reputation: 40773

The problem is in class B, you only have the property for p1, without a setter. That makes p1 a read-only property. In class A, at the line:

    self.p1 = p1

you will get the AttributeError because you are trying to overwrite a read-only property. The fix is to add a setter for class B:

@p1.setter
def p1(self, p1):
    print('Setting B.p1 = {}'.format(p1))
    self._p1 = p1

With this addition, re-run your code and you will notice the print output. Once happy, you can remove that print line.

Upvotes: 1

buran
buran

Reputation: 14273

You need to define @p1.setter also for class B

class A:
    def __init__(self, p1, p2):
        self.p1 = p1
        self.p2 = p2

    @property
    def p1(self):
        return self._p1
    @p1.setter
    def p1(self, p1):
        self._p1 = p1

    @property
    def p2(self):
        return self._p2
    @p2.setter
    def p2(self, p2):
        self._p2 = p2

class B(A):
    def __init__(self, p1, p2, p3):
        super(B, self).__init__(p1, p2)
        self.p3 = p3

    @property
    def p1(self):
        return self._p1 if self.p3 is None else self._p1+1

    @p1.setter
    def p1(self, p1):
        self._p1 = p1

    @property
    def p3(self):
        return self._p3
    @p3.setter
    def p3(self, p3):
        self._p3 = p3

b1 = B(1, 2, 3)
b2 = B(1, 2, None)

print(b1.p1)
print(b2.p1)

output

2
1

Upvotes: 2

Related Questions