I am working with models of neurons. One class I am designing is a cell class which is a topological description of a neuron (several compartments connected together). It has many parameters but they are all relevant, for example:
number of axon segments, apical bifibrications, somatic length, somatic diameter, apical length, branching randomness, branching length and so on and so on... there are about 15 parameters in total!
I can set all these to some default value but my class looks crazy with several lines for parameters. This kind of thing must happen occasionally to other people too, is there some obvious better way to design this or am I doing the right thing?
UPDATE: As some of you have asked I have attached my code for the class, as you can see this class has a huge number of parameters (>15) but they are all used and are necessary to define the topology of a cell. The problem essentially is that the physical object they create is very complex. I have attached an image representation of objects produced by this class. How would experienced programmers do this differently to avoid so many parameters in the definition?
class LayerV(__Cell): def __init__(self,somatic_dendrites=10,oblique_dendrites=10, somatic_bifibs=3,apical_bifibs=10,oblique_bifibs=3, L_sigma=0.0,apical_branch_prob=1.0, somatic_branch_prob=1.0,oblique_branch_prob=1.0, soma_L=30,soma_d=25,axon_segs=5,myelin_L=100, apical_sec1_L=200,oblique_sec1_L=40,somadend_sec1_L=60, ldecf=0.98): import random import math #make main the regions: axon=Axon(n_axon_seg=axon_segs) soma=Soma(diam=soma_d,length=soma_L) main_apical_dendrite=DendriticTree(bifibs= apical_bifibs,first_sec_L=apical_sec1_L, L_sigma=L_sigma,L_decrease_factor=ldecf, first_sec_d=9,branch_prob=apical_branch_prob) #make the somatic denrites somatic_dends=self.dendrite_list(num_dends=somatic_dendrites, bifibs=somatic_bifibs,first_sec_L=somadend_sec1_L, first_sec_d=1.5,L_sigma=L_sigma, branch_prob=somatic_branch_prob,L_decrease_factor=ldecf) #make oblique dendrites: oblique_dends=self.dendrite_list(num_dends=oblique_dendrites, bifibs=oblique_bifibs,first_sec_L=oblique_sec1_L, first_sec_d=1.5,L_sigma=L_sigma, branch_prob=oblique_branch_prob,L_decrease_factor=ldecf) #connect axon to soma: axon_section=axon.get_connecting_section() self.soma_body=soma.body soma.connect(axon_section,region_end=1) #connect apical dendrite to soma: apical_dendrite_firstsec=main_apical_dendrite.get_connecting_section() soma.connect(apical_dendrite_firstsec,region_end=0) #connect oblique dendrites to apical first section: for dendrite in oblique_dends: apical_location=math.exp(-5*random.random()) #for now connecting randomly but need to do this on some linspace apsec=dendrite.get_connecting_section() apsec.connect(apical_dendrite_firstsec,apical_location,0) #connect dendrites to soma: for dend in somatic_dends: dendsec=dend.get_connecting_section() soma.connect(dendsec,region_end=random.random()) #for now connecting randomly but need to do this on some linspace #assign public sections self.axon_iseg=axon.iseg self.axon_hill=axon.hill self.axon_nodes=axon.nodes self.axon_myelin=axon.myelin self.axon_sections=[axon.hill]+[axon.iseg]+axon.nodes+axon.myelin self.soma_sections=[soma.body] self.apical_dendrites=main_apical_dendrite.all_sections+self.seclist(oblique_dends) self.somatic_dendrites=self.seclist(somatic_dends) self.dendrites=self.apical_dendrites+self.somatic_dendrites self.all_sections=self.axon_sections+[self.soma_sections]+self.dendrites
Functions with three arguments (triadic function) should be avoided if possible. More than three arguments (polyadic function) are only for very specific cases and then shouldn't be used anyway.
The ideal number of arguments for a function is zero (niladic). Next comes one (monadic), followed closely by two (dyadic). Three arguments (triadic) should be avoided where possible. More than three (polyadic) requires very special justification - and then shouldn't be used anyway.
In the Java edition of Building Maintainable Software, Joost Visser advises keeping the number of parameters to no more than four. The same guideline probably applies to almost all other programming languages, like C#, Scala and even FORTRAN and COBOL.
UPDATE: This approach may be suited in your specific case, but it definitely has its downsides, see is kwargs an antipattern?
Try this approach:
class Neuron(object): def __init__(self, **kwargs): prop_defaults = { "num_axon_segments": 0, "apical_bifibrications": "fancy default", ... } for (prop, default) in prop_defaults.iteritems(): setattr(self, prop, kwargs.get(prop, default))
You can then create a Neuron
like this:
n = Neuron(apical_bifibrications="special value")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With