Dan Cohen
Dan Cohen

Reputation: 81

Method of a superclass is not being inherited by a subclass

I'm following book about object oriented Python and I stumbled upon code that quite doesn't make sense to me:

class Property:

    def __init__(self, square_feet='', beds='', baths='', **kwargs):
        super().__init__(**kwargs)
        self.square_feet = square_feet
        self.num_bedrooms = beds
        self.num_baths = baths

    def display(self):
        print('PROPERTY DETAILS')
        print('----------------')
        print(f'square footage: {self.square_feet}')
        print(f'bedrooms: {self.num_bedrooms}')
        print(f'bathrooms: {self.baths}')
        print()

    def prompt_init():
        return dict(square_feet=input('Enter the square feet: '),
                beds=input('bedrooms: '), baths=input('baths: '))

    def get_valid_input(input_string, valid_options):
        input_string += ' ({}) '.format(', '.join(valid_options))
        response = input(input_string)
        while response.lower() not in valid_options:
            response = input(input_string)
        return response

    prompt_init = staticmethod(prompt_init)

then I have:

class House(Property):
    valid_garage = ('attached', 'detached', 'none')
    valid_fenced = ('yes', 'no')

    def __init__(self, num_stories='', garage='', fenced='', **kwargs):
        super().__init__(**kwargs)
        self.garage = garage
        self.fenced = fenced
        self.num_stories = num_stories

    def display(self):
        super().display()
        print('HOUSE DETAILS')
        print(f'# of stories: {self.num_stories}')
        print(f'garage: {self.garage}')
        print(f'fenced yard: {self.fenced}')

    def prompt_init():
        parent_init = Property.prompt_init()
    --> fenced = get_valid_input('Is the yard fenced ? ',   House.valid_fenced)
        garage = get_valid_input('Is there a garage ? ', House.valid_garage)
        num_stories = input('How many stories ? ')

        parent_init.update({
            'fenced': fenced,
            'garage': garage,
            'num_stories': num_stories
        })
        return parent_init
        prompt_init = staticmethod(prompt_init)


class Rental:

    def __init__(self, furnished='', utilities='', rent='', **kwargs):
        super().__init__(**kwargs)
        self.furnished = furnished
        self.utilities = utilities
        self.rent = rent

    def display(self):
        super().display()
        print('RENTAL DETAILS')
        print(f'rent: {self.rent}')
        print(f'estimated utilities: {self.utilities}')
        print(f'furnished: {self.furnished}')

    def prompt_init():
        return dict(
            rent=input('What is the monthly rent ? '), utilities=input('What are the estimated utilities ? '),
            furnished=input('Is the property furnished ? ', ('yes', 'no')))
    prompt_init = staticmethod(prompt_init)


class HouseRental(Rental, House):

    def prompt_init():
        init = House.prompt_init()
        init.update(Rental.prompt_init())
        return init
    prompt_init = staticmethod(prompt_ini

when I instantiate HouseRental class like this:

init = HouseRental.prompt_init()

I'm getting bunch of prompts as expected but I'm also getting error

get_valid_input not defined

on the line I marked with -->, Which doesn't make sense to me because the method is defined in Property superclass and House class is a subclass of Property which inherits all methods Property have.

How come House class isn't recognizing the method?

Upvotes: 3

Views: 92

Answers (2)

Engineero
Engineero

Reputation: 12918

Pass self as the first argument to your prompt_init method in House, and call the inherited method with self.get_valid_inputs(...).

In your House class:

def prompt_init(self):
    parent_init = Property.prompt_init()
    fenced = self.get_valid_input('Is the yard fenced ? ',   House.valid_fenced)
    garage = self.get_valid_input('Is there a garage ? ', House.valid_garage)
    num_stories = input('How many stories ? ')
    # ...

You also have to pass self as the first argument of the parent class's get_valid_input method. This is because Python automatically passes a reference to the calling object as the first argument to class methods, so if you do not account for that in your signature, you will get "too many arguments" errors.

In your Property class:

def get_valid_input(self, input_string, valid_options):
    input_string += ' ({}) '.format(', '.join(valid_options))
    response = input(input_string)
    # ...

Then house = House().prompt_init() ran without errors for me.

It looks like you might need to add self as an argument to all of your other prompt_init methods for your subclasses. Generally you should always pass self as the first argument to methods in a class.

Upvotes: 1

Dan Cohen
Dan Cohen

Reputation: 81

What worked for me was pulling the method out of the superclass and leaving it in global scope like this:

def get_valid_input(input_string, valid_options):
    input_string += ' ({}) '.format(', '.join(valid_options))
    response = input(input_string)
    while response.lower() not in valid_options:
        response = input(input_string)
    return response


class Property:

    ...
    # other methods
    ...


class House(Property):

    ...
    # other methods
    ...

    def prompt_init():
        parent_init = Property.prompt_init()
        fenced = get_valid_input('Is the yard fenced ? ', House.valid_fenced)
        garage = get_valid_input('Is there a garage ? ', House.valid_garage)
        num_stories = input('How many stories ? ')

        parent_init.update({
            'fenced': fenced,
            'garage': garage,
            'num_stories': num_stories
        })
        return parent_init


class HouseRental(Rental, House):

    def prompt_init():
        init = House.prompt_init()
        init.update(Rental.prompt_init())
        return init
    prompt_init = staticmethod(prompt_init)

Upvotes: 0

Related Questions