0

I am a Python novice and I am having difficulty with inheritance and using super()

The code below is giving me this error

Exception has occurred: AttributeError 'ObjB' object has no attribute 'job'

But I'm not sure why as job is an attribute of ObjB

The test code is this..

class ObjA():
    def __init__(self, astr):
        self.name = astr
        self.decorate()

    def decorate(self):
        self.name = '['+self.name+']'

class ObjB(ObjA):
    def __init__(self, aname, ajob):
        super().__init__(aname)
        self.job = ajob

    def decorate(self):
        super().decorate()
        self.name = self.name + ' is a ' + self.job

test = ObjA('Fred')
print(test.name)

test2 = ObjB('Fred', 'Baker')
print(test2.name)

What I was expecting was this

[Fred]
[Fred] is a Baker

2 Answers 2

3

In your ObjB.__init__() method you are calling super().__init__(aname) before you set self.job = ajob, so that when the decorate methods are called, the self.job is not yet set. Try moving the self.job = ajob earlier in the __init__() method, like:

class ObjB(ObjA):
    def __init__(self, aname, ajob):
        self.job = ajob
        super().__init__(aname)

Another way to fix the problem is to eliminate the decorate() methods completely:

class ObjA():
    def __init__(self, astr):
        self.name = '['+astr+']'


class ObjB(ObjA):
    def __init__(self, aname, ajob):
        super().__init__(aname)
        self.job = ajob
        self.name = self.name + ' is a ' + self.job
Sign up to request clarification or add additional context in comments.

2 Comments

Yes, this does correct the problem, but it is caused by the fact that I was not expecting the __init__ on ObjA to call the decorate method on ObjB. Can this be avoided?
I have edited my answer above to include another possibility that eliminates the decorate() methods completely.
0

The key thing is that when you use super in subclass to call __init__ in base class, the self passed to __init__ is the instance of subclass ObjB rather than ObjA. Therefore, the self.decorate() in ObjA's __init__ calls actually the decorate method in ObjB, that's why the job is not defined.

super().__init__ functions like this: ObjA.__init__(test2)

Below comes from Python docs about inheritance

Derived classes may override methods of their base classes. Because methods have no special privileges when calling other methods of the same object, a method of a base class that calls another method defined in the same base class may end up calling a method of a derived class that overrides it.

2 Comments

Ok. When creating ObjB, what I want is the decorate method of ObjA to be called by ObjA's __init__ and the decorate method of ObjB to be called by ObjB's init is there a way to achieve this or do i need to restructure my class to not call the decorate method from the __init__?
@CHaste One way is using ObjA.decorate(self) in your __init__ method but this is a bad practice. I think you need a clear design of structure. If ObjA is meant to inherited and methods are to be overwritten, then be careful to call methods in ObjA because it may be overwritten by subclasses.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.