Instance of one class to contain arbitrary number of instances of another class in Python I'm trying to see if there is a better way to design this. I have a class Animal that is inherited by Male and Female classes (Female class has an additional attribute). I also have a class called Habitat, an instance of each would contain any number of Animals including 0.

class Animal:

    def __init__(self, life_span=20, age=0):
        self.__life_span = life_span
        self.__age = age

    def get_life_span(self):
        return self.__life_span

    def get_age(self):
        return self.__age

    def age(self):
        self.__age += 1


class Female(Animal):

    __gender = 'female'

    def __init__(self, pregnant=False):
        self.__pregnant = pregnant

    def impregnate(self):
        self.__pregnant = True


class Male(Animal):

    __gender = 'male'


class Habitat:

    def __init__(self, list_of_animals=[Male(), Female()]): 
        self.__list_of_animals = list_of_animals

    def __add_male(self):
        self.__list_of_animals.append(Male())

    def __add_female(self):
        self.__list_of_animals.append(Female())

    def add_animal(self):
        if random.choice('mf') == 'm':
            self.__add_male()
        else:
            self.__add_female()    

    def get_population(self):
        return self.__list_of_animals.__len__()


Before I add any more functionality, I would like to find out if that's a proper way to design these classes. Maybe there is a design pattern I can use? I'm new to OOP, any other comments/suggestions are appreciated.
In Habitat.__init__, you've committed a classic beginner's fallacy: using a list as a default argument.

In Python, every call to a function with a default argument will use the same default object. If that object is mutable (e.g. a list) any mutations to that object (e.g. .append) will affect that one object. In effect, all your Habitats will end up using the exact same list unless you specify a non-default argument.

Instead, use None as the default argument, and test for it:

def __init__(self, animals=None):
    if animals is None:
        animals = [Male(), Female()]