3

I am trying to make a subclass from a class with a @classmethod defined:

class Pet(object):
    def __init__(self,animal):
        self.animal = animal

    @classmethod
    def wild(cls,animal):
        return cls('wild '+animal)

class Cat(Pet):
    def __init__(self):
        Pet.wild('cat')

if __name__ == '__main__':
    print Cat().animal

This gives me the following error:

print Cat().animal
AttributeError: Cat instance has no attribute 'animal'

Probably I don't fully understand the concept of subclassing, I have been also trying to pass self to Pet.wild without much more success. Any help would be really appreciated!

EDIT

I try to explain what I want to do: I would like to initialize parentclass (or superclass?) Pet from the Cat subclass using the classmethod wild and not using __init__. Is this possible? Thank you

1
  • 1
    you need to call Pet.__init__() in Cat.__init__() for self.animal to be defined Commented Nov 18, 2015 at 16:29

2 Answers 2

4

That is because you are not calling super to properly inherit from your base class. So, doing this:

Pet.wild('cat')

does not do what you expect.


class Pet(object):
    def __init__(self,animal):
        self.animal = animal

    @classmethod
    def wild(cls,animal):
        return cls('wild '+animal)

class Cat(Pet):
    def __init__(self):
        super(Cat, self).__init__('cat')

if __name__ == '__main__':
    print Cat().animal
Sign up to request clarification or add additional context in comments.

4 Comments

furthermore, "Pet.wild('cat')" does nothing (this is a function, returning new object, and discarding it)
The animal = 'pig' in your answer does nothing.
It was a copy paste from OP. I can remove it.
Yes, this is the "standard" subclassing. But if I want to get 'wild cat' as initialization of animal this does not work. My idea was to try to initialize the Cat class without calling directly Pet.__init__() but just by using the other classmethod
2

So if you want to add inheritance and extend Cat later here is how you would do it. See this post for the difference between __new__ and __init__

class Pet(object):

    def __init__(self, animal):
        self.animal = animal

    @classmethod
    def wild(cls, animal):
        obj = cls.__new__(cls)
        obj.animal = "wind " + animal
        return obj 

class Cat(Pet):
    pass


if __name__ == "__main__":
    print Pet.wild("cat").animal
    cat = Cat.wild("cat")
    house_cat = Cat("cat")
    print house_cat.animal, cat.animal

Here is what is going on under the covers. Cat inherits the wild classmethod too. So you don't have to call Pet.wild from within Cat constructor. You just call the wild classmethod directly on Cat. cls gets the Cat class and so the object created will be Cat instance and not a Pet instance. However, at some point you will have to override some default behavior in constructor and that involves some amount of coding.

5 Comments

thanks, but say that more in general I don't want to re-pass "cat" all the time and add some specific attributes to the Cat which Pet does not have. By my understanding that's the idea of making subclasses, this is just a simplified example.
If you write an __init__ method in your subclass, it will override the Pet init method. The only way to get animal attribute is to call the Parent class' init method. Also init is different in a way that it doesn't return anything. So your return statement doesn't do anything within init
thanks a lot! I didn't realize I was overwriting __init__. But then why don't I get an error when I call Pet.wild('cat')? If I understood correctly, this should than call the Cat.__init__ (if I have overwritten Pet.__init__) which does not allow any input
The code snippet above does not call __init__ explicitly. If you want that you should change the __new__ to __init__. Which would call the default constructor and then you can just override the attributes you want to be different in a wild Pet
Also see my edit to the answer which shows how to use the classmethod from subclasses.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.