0

I'm trying to create a subclass in a particular case and I can not attach attributes or method to it. I think the new / init usage is not clear to me but I could not find ways to do that from the internet.

Here is a minimal working toy example showing what I am trying to do.

---- Edit of create_special_human() function

# I have this
class Human():
    def __init__(self):
        self.introduction = "Hello I'm human"


def create_special_human():
    special_human = do_very_complicated_stuffs() #returns type Human
    special_human.introduction = "Hello I'm special"
    return special_human


# I want to create this class
class SuperHero(Human):

    def __new__(self):
        special_human = create_special_human()
        return special_human

    def __init__(self):
        self.superpower = 'fly'

    def show_off(self):
        print(self.introduction)
        print(f"I can {self.superpower}")



human = Human()
special_human = create_special_human()
super_hero = SuperHero()
super_hero.show_off() # fails with error "type object 'Human' has no attribute 'show_off'"
print(super_hero.superpower) # fails with error "type object 'Human' has no attribute 'superpower'"

I want to create the subclass Superhero, and I need to initialize it with what is returned by create_special_human(), because this function is very complex in the real case. Moreover, I can not modify the Human class and create_special_human().

I am aware that the returned type is Human, which is wrong, but I don't know why that happens.

Mai Kar
  • 138
  • 1
  • 3
  • 18
  • I don't think you can do what you want. See this [answer](https://stackoverflow.com/a/17513146) which explains that if `__new__` returns a different type, then `__init__` is not called. – quamrana Jan 29 '21 at 21:26
  • I can get rid of the `__init__` by adding the `superpower` attribute in the`__new__` method. But if I do that I still have the issue of the `show_off` method being not recognized. – Mai Kar Jan 29 '21 at 21:32
  • Can you add `do_very_complicated_stuffs(self)` to the `SuperHero.__init__`? Why use `__new__`? – OneCricketeer Jan 29 '21 at 21:33
  • @OneCricketeer Good question, actually in my real case I can not, let me modify my toy example. I'll modify create_special_human() to match better my situation. – Mai Kar Jan 29 '21 at 21:41
  • `do_very_complicated_stuffs()` happens to return an object of type `Human`, but it is build from many layers.The initial`Human()` initializer behind it is digged very deeply. That's why I can not just copy this code in my `__init__` – Mai Kar Jan 29 '21 at 21:46
  • Okay, so the issue is that you are always returning entirely new objects, and have no need for inheritance... – OneCricketeer Jan 29 '21 at 21:54
  • I have need for inheritance, basically I want to create methods for the object created by `create_special_human` so that I can manipulate it more easily. – Mai Kar Jan 29 '21 at 22:07
  • It boils down to `do_very_complicated_stuffs()` should create the right instance in the first place. – quamrana Jan 29 '21 at 22:40
  • Yes but that's not up to me, I'm using an existing library. I just want to know if this is possible or not. If it is not, why? Why can't I initialize a class instance with a custom object? – Mai Kar Feb 04 '21 at 21:12

1 Answers1

0

(Edited) I've made few changes to your code and it is executing successfuly.

  • You must call superclass __init__ inside of a subclass __init__:
  • As I said in the comment, simply return SuperHero from create_special_human.
  • I've removed __new__ method from SuperHero since it doesn't make any sense. Take a look at this article
class Human():
    def __init__(self):
        self.introduction = "Hello I'm human"


class SuperHero(Human):
    
    # Removed __new__

    def __init__(self):
        super().__init__()  # Init superclass
        self.superpower = 'fly'

    def show_off(self):
        print(self.introduction)
        print(f"I can {self.superpower}")


def create_special_human():
    # Simply initialize and return SuperHero instance
    special_human = SuperHero()
    do_very_complicated_stuffs(special_human)
    special_human.introduction = "Hello I'm special"
    return special_human


human = Human()
special_human = create_special_human()
super_hero = SuperHero()
super_hero.show_off() 
print(super_hero.superpower)

You can read more about super() in this question.

nenadp
  • 798
  • 1
  • 7
  • 15
  • But I need to initialize my SuperHero() object with the result of the function create_special_human(). – Mai Kar Jan 29 '21 at 21:08
  • Then simply return `SuperHuman` instance, do exactly as you would in `__main__` – nenadp Jan 29 '21 at 21:11
  • Could you please update your answer with what you propose? I'm not sure I see what you mean. – Mai Kar Jan 29 '21 at 21:21
  • Just updated, your code with a few changes – nenadp Jan 29 '21 at 21:50
  • The SuperHero object is still not initialized by the output of create_special_human(). I also updated my code to correct the `create_special_human` function. – Mai Kar Feb 04 '21 at 22:20
  • i think you should explain a bit better what you are trying to achieve (from a more zoomed put view). I think a “special” constructor in a @classmethod would do the job, but i am guessing your intent. – Lars Nov 27 '21 at 10:30