I've been working through Genetic Algorithms with Python by Clinton Sheppard. I like it a lot. One of the things I like about it is that the author takes a lot of different examples, and step-by-step teaches you the elements of genetic algorithms, and also improves the algorithms over the course of the book.
I'd say if you want to learn genetic algorithms this is certainly a good book. I'll be looking for some more theoretical books to round out my knowledge, but this is a great start for someone who knows python, but isn't super familiar with how genetic algorithms work.
One of the things I don't like about the book is that it doesn't actually talk about the overall concept of what genetic algorithms do in a way that makes it super easy to apply to other problems. I do think the point of the step-by-step approach was to give you some of that, but somehow it didn't quite work for me I needed a little bigger picture explanations of the conceptual frameworks behind the code that he uses.
But the author does, with each subsequent chapter, add new, more complex concepts and new ways to do mutation and checking fitness, which is great.
Here's a little distillation I got from doing most of the exercises in the book.
The basic idea of genetic algorithims is something I've actually known about for a long time. The idea is to use the basic concepts of mutation and fitness to solve problems more organically than systematically as other kinds of algorithms do.
So first we need a function (the author of the book has you create a function called genetic.py) that does the core of the work - it generates the "parents" and "children", does the mutation and gets the best child, based upon how fit the child is.
Then, there are a set of problem-specific functions. We need to figure out what "fitness" means, which will be problem-specific. For example, guessing a text snippet, the fitness is just how close (or far) the genetically generated text is from the target. For sorting a list of numbers, the fitness is checking the neighbors of a number in the list, to see if they are properly less than, or greater than the number you're checking.
So you also need a set of functions that define the geneset (which will be different for each problem,) and defines the fitness for that specific problem. In addition, each problem can use slightly different mutation strategies (mutating more than one variable, hill climbing, etc.) and will also need different ways to display the results.
I'll probably be writing more about this as I dive into how to apply this to some specific problems I'm working on.
One more thing to add - I learned a bit about what distinguishes genetic algorithms from genetic programming. The latter is a process where programs themselves are created and mutated so that they can perform actions and those actions are tested for fitness. (For instance, a program which can recognize faces, or a program which creates a virtual bot that can walk.) Genetic programming needs to be done using languages that are amenable to modification (like Lisp/Scheme.) Genetic algorithims are really manipulating data - so they can be written in any language (like Python.)