After programming in Haskell for a while, I've gotten attached to a functional style.  This is clearly evident in the code for my genetic algorithm. Could you provide me with some hints as to how I can make this code more pythonic?  By that, I mean provide some method of organisation rather than throwing a bunch of functions around.  Any other recommendations are also welcome.import copyimport matplotlib.pyplot as pyplotimport randomdef create_member(genes):    return (sum(genes), genes)def shuffle(pool):    pool_shuffled = copy.deepcopy(pool)    random.shuffle(pool_shuffled)    return pool_shuffleddef calculate_pool_fitness(pool):    return sum([member[0] for member in pool])def calculate_member_fitness(member):    return sum(member[1])def recalculate_fitneses(pool):    return [(calculate_member_fitness(member), member[1]) for member in pool]def select_members_roulette(pool, count):    selection = []    while len(selection) < count:        member = select_member_roulette(pool)        selection.append(copy.deepcopy(pool[member]))    return selectiondef select_member_roulette(pool):    drop = random.randint(0, calculate_pool_fitness(pool))    total_fitness = 0    for member in range(0, len(pool)):        total_fitness += pool[member][0]        if total_fitness >= drop:            return memberdef mutate_gene(gene, rate=1):    return 1 - gene if random.random() <= rate else genedef mutate_genes(genes, rate=1):    return [mutate_gene(gene, rate) for gene in genes]def mutate_member(member, rate=1):    return member[0], mutate_genes(member[1], rate)def mutate_pool(pool, rate=1):    return [mutate_member(member, rate) for member in pool]def create_random_gene():    return random.choice([0, 1])def create_random_genes(size):    return [create_random_gene() for _ in range(size)]def crossover_genes(mother, father, rate=1):    if random.random() <= rate:        split = random.randint(1, len(mother))        daughter = mother[:split] + father[split:]        son = father[:split] + mother[split:]    else:        daughter = copy.deepcopy(mother)        son = copy.deepcopy(father)    return daughter, sondef crossover_members(mother, father, rate=1):    daughter_genes, son_genes = crossover_genes(mother[1], father[1])    return [(mother[0], daughter_genes), (father[0], son_genes)]def crossover_pool(pool, rate=1):    children = []    # select every two elements for crossover    for mother, father in zip(pool[::2], pool[1::2]):        children.extend(crossover_members(mother, father, rate))    return childrendef generate_pool(size, gene_size):    pool = []    for member in range(0, size):        genes = create_random_genes(gene_size)        pool.append(create_member(genes))    return pooldef evolve(pool, rate_crossover=0.9, rate_mutation=0.01):    successors = copy.deepcopy(pool)    # perform roulette selection whilst keeping best member    member_alpha = copy.deepcopy(max(successors, key=lambda member: member[0]))    successors = select_members_roulette(pool, len(pool) - 1)    successors.append(member_alpha)    successors = shuffle(successors)    successors = crossover_pool(successors, rate_crossover)    successors = mutate_pool(successors, rate_mutation)    successors = recalculate_fitneses(successors)    return successorsdef main():    random.seed    pyplot.figure(figsize=(14, 8), dpi=400)    axgraph=pyplot.subplot(111)    pool_size = 50    gene_size = 50    generations = 100    pool = generate_pool(pool_size, gene_size)    for generation in range(0, generations):        pool = evolve(pool)        axgraph.scatter(generation, sum([member[0] for member in pool]))    pyplot.grid(True)    pyplot.axis([0, generations, 0, pool_size * gene_size])    pyplot.savefig('genetic_algorithms.png')main()if __name__ == '__main__':    main()
Organising code for a genetic algorithm in Python
python;ai
I have been facing the same issue for a few months, even though I didn't write that much functional code before switching. Please take my comments with a grain of salt even if I say do this instead of this might help but I'm not sure.Use dictionaries instead of tuples:def create_member(genes):    return {'sum': sum(genes), 'genes': genes}Use generators instead of list-expressions:def mutate_pool(pool, rate=1):    for member in pool:        yield mutate_member(member, rate)Yay, lazy lists! (kind of...)Write code for the next person which will be reading it. You shouldn't put comments only where you had some trouble ([::2] selects one gene out of two) but try to make any function easy to understand and modify in isolation.Prefer longer functions and document them using docstrings. A nice function name is usually not enough for documentation:def mutate_genes(genes, rate):        Given a list of genes, flip some of them according to rate.        for gene in genes:        yield 1 - gene if random.random() <= rate else genedef mutate_pool(pool, rate=1):        Returns a new pool of member where every bit in every gene could have been    flipped according to rate.        for member in pool:        yield member[0], mutate_genes(member[1], rate)Of course those examples are a bit artificial but they do feel more pythonic. You don't have to document every function, just think about your readers. :)Read nice Python code. I'd recommend Django and scikit-learn (Those are links to specific files that I chose randomly.)I think it's worthwhile to try to force yourself to write pythonic code for some time so that you can tell what's nice in the Python way and what's actually better in a functional style.