Your breed_and_select function can be more succinctly written as:
import operator
def breed_and_select_fittest(individual):
"""Return the fittest member of a generation."""
generation = Organism.spawn(individual)
return min(generation, key=lambda member: memberkey=operator.fitnessattrgetter("fitness"))
It is better to use operator.attrgetter than lambda here, because it is faster (even though performance is not your limiting factor, your execution time is dominated by the time.sleep(0.2) right now).
I would also make this slightly more customizable by adding the size of each generation and the variation during the spawning as parameters.
I'm also not convinced spawn should really be a @classmethod. After all it is the individual spawning the next generation. Consider this:
import operator
class Organism:
...
def spawn(self, n=10, variance=10):
"""Return a mutated generation of `n` members."""
return [self.__class__(*self.mutate(variance)) for _ in range(n)]
def mutate(self, variance):
for value in (self.r, self.g, self.b):
yield randint(value - variance, value + variance)
...
def breed_and_select_fittest(individual):
"""Return the fittest member of a generation."""
generation = individual.spawn()
return min(generation, key=operator.attrgetter("fitness"))
Note that the default start value for range is already 0, so no need for that.
I also substituted the lambda for operator.attrgetter, because its should be faster (even though performance is not your limiting factor, your execution time is dominated by the time.sleep(0.2) right now).