Search code examples
pythonpython-3.xinheritanceinstance-variablesclass-variables

Python accessing parent class variable as instant variable in child class


I'm trying to access instance variables of a parent class as class variables in a child class.

The purpose is that the parent class will have a lot of child classes which all need to have the same structure, and a lot of different people will be working with and creating these child classes, without needing to know the inner workings of the parent class. Here's my example:

class Human(ABC):

    def __new__(cls, *args, **kwargs):
        cls.human_name = args[0]
        cls.source = f'database_{cls.__name__}'.lower()
        return super().__new__(cls)

    @property
    @abstractmethod
    def query(self):
        pass


class Company:
    class Employee(Human):
        query = f'SELECT {human_name} FROM {source};'

        # these two functions are just for testing and will not be in the final product
        def print_something(self):
            print(self.human_name)

        def print_source(self):
            print(self.source)


e = Company.Employee('John')
print(e.human_name)
print(e.query)
e.print_source()

I want to be able to create a child class of parent class Human (structured together in Company) where I only need to define the query variable which should automatically recognise the variables human_name and source.

How would I go about making this as simple as possible? Is this even possible? Many thanks!


Solution

  • So, you need to actually implement the property.

    class Human(ABC):
    
        def __new__(cls, *args, **kwargs):
            cls.human_name = args[0]
            cls.source = f'database_{cls.__name__}'.lower()
            return super().__new__(cls)
    
        @property
        @abstractmethod
        def query(self):
            pass
    
    
    class Company:
        class Employee(Human):
            @property
            def query(self):
                return f'SELECT {self.human_name} FROM {self.source};'
    
            # these two functions are just for testing and will not be in the final product
            def print_something(self):
                print(self.human_name)
    
            def print_source(self):
                print(self.source)
    
    
    e = Company.Employee('John')
    print(e.human_name)
    print(e.query)
    e.print_source()
    

    Note, however, since __new__ creates class variables... this query will always be the same across instances:

    employee1 = Company.Employee('John')
    employee2 = Company.Employee('Jack')
    
    print(employee1.query)
    print(employee2.query)
    

    will print:

    SELECT Jack FROM database_employee;
    SELECT Jack FROM database_employee;