> # This program simulates the random branching and extinction of linages. > # It also mutates a series of characters representing morphology at > each branch point > # The program replicates the program first described by D.M. Raup and > S.G. Gould > # 1974 Systematic Zoology 23: 305-322. > # written by Vincent Wan with help from tutor@python.org
Put the above set of comments in triple quotes and it will become a *docstring* and hence accessible via Pythons help() function... > import random > > debug = 0 # turns debug diagnostic printing on = 1 or off = 0 > > #constants that control the simulation > max_linages = 201 # the number of linage to be evolved + 1 > branching_probablity = .1 > extinction_probablity = .1 > mutation_rate = .5 Constants should be in UPPER_CASE by convention. > # initalize > living_linages = [[0, 0, 0, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]] # the > ancestor > dead_linages = [] > tree = "*0*" > time = 0 > next_linage = 0 > > def Mutate_morphology(a_morphology, rate): the fashion for function naming is to separewt words with capitals so this would be mutateMorphology(...) Names starting upper case are conventionally classes. So a Python reader may think the function call is a class instatiation as it is. > "Each morphological character has a rate chance it is increased or > decreased by 1" > a_morphology = a_morphology[:] > character = 0 > while character < len(a_morphology): > if random.random() <= rate: > if random.random() < .5: .5 would be clearer as 0.5, the point on its own is easily missed. > a_morphology[character] = a_morphology[character] - 1 > else:a_morphology[character] = a_morphology[character] + 1 You could use += and -+ here to save a wee bit of space. > character += 1 > return a_morphology > > def Braching(debug, next_linage, time, living_linages, mutation_rate, > tree): > "With branching_probablity creates a new linage, mutates its > morphology, and updates tree." > counter = 0 > while counter < len(living_linages): > if random.random() < branching_probablity: > # creates new linage > next_linage += 1 > new_linage = [next_linage, time, 0, > Mutate_morphology(living_linages[counter][3], mutation_rate)] better to line this up with the other parameters: new_linage = [next_linage, time, 0, Mutate_morphology(living_linages[counter][3], mutation_rate)] it keeps the block structure clear. > living_linages.append(new_linage) > # updates linage tree > target = '*' + str(living_linages[counter][0]) + '*' > replacement = '(' + target + ',*' + str(new_linage[0]) + > '*)' You could use string formatting to do both lines in one: replacement = "(*%s*,*%s*)" % (living_linages[counter][0], new_linage[0]) it will be faster too. > tree = tree.replace(target, replacement) Ah, but here you use both bits.... Ok, but you could still use formatting to create the two strings. > counter += 1 > if debug: print 'at time ', time, ' living_linages: ', > [linage[0] for linage in living_linages] > return (next_linage, living_linages, tree) > > def Extinction(debug, extinction_probablity, living_linages, time, > dead_linages): > "With extinction_probablity kills living species and adds them to > the dead list" > counter = 0 > while counter < len(living_linages): > if random.random() < extinction_probablity: > newly_dead = living_linages[counter] > newly_dead[2] = time > dead_linages.append(newly_dead) > living_linages.remove(living_linages[counter]) > if len(living_linages) == 0: break # when the last > living_linages goes extinct exit > counter += 1 there may be a subtle bug here. IF you remnove an entry above then all the elements shuffle up one. If you now increment counter you will in effect step over one entry without checking it. Is that what you want? > if debug: print 'at time ', time, ' dead_linages : ', [linage[0] > for linage in dead_linages] > return (living_linages, dead_linages) > > def Print_results(next_linage, max_linages, living_linages, > dead_linages, tree): > "prints number of linages, the data about the linages living and > dead, and the tree" > if next_linage < max_linages: > print '\nall extinct with only ', next_linage + 1, ' linage of > ', max_linages > else: > print '\n', max_linages - 1, ' linages evolved' > print '\nliving linages:' > for each in living_linages: > print 'linage', each[0], 'born', each[1], 'morphology:', each[3] > print '\nextinct linages: ' > for each in dead_linages: > print 'linage', each[0], 'born', each[1], '- died', each[2] > print 'morphology:', each[3] > tree = tree.replace('*','') > print '\ntree (in New Hampshire form: )', tree > > # main loop > while next_linage < max_linages: > # handles branching > (next_linage, living_linages, tree) = Braching(debug, next_linage, > time, living_linages, mutation_rate, tree) > # handles extinction > (living_linages, dead_linages) = Extinction(debug, > extinction_probablity, living_linages, time, dead_linages) > if len(living_linages) == 0: break # when the last > living_linages goes extinct exit > time += 1 > > Print_results(next_linage, max_linages, living_linages, dead_linages, > tree) might be nicer to put the main code in a main function and then use the magic incantation if __name__ == '__main__': main() to execute it. It allows for easier extension of your code by using your file as a module, and also allows you to experiment with it from the Python prompt by importing it without the main code executing. These are nearly all style comments and as such are subjective and open do debate, but I hope they are helpful. Looks like another good candidate for Useless Python... Alan G. _______________________________________________ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor