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.
1 Answer 1
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 Habitat
s 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()]
Explore related questions
See similar questions with these tags.
obj.__len__()
, uselen(obj)
instead. Also, no need to use name mangling (double leading underscores): Just useself.age
orself._age
, especially use the former in favor of trivial getters (you can later replace them with aproperty
, if you need that extra power, without changing the way client code works with your objects). \$\endgroup\$