Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class with too many parameters: better design strategy?

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?

enter image description here

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 
like image 805
Mike Vella Avatar asked May 05 '11 14:05

Mike Vella


People also ask

How many parameters is too many for a method?

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.

How many parameters should a method have?

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.

How many parameters is too much Java?

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.


1 Answers

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") 
like image 112
blubb Avatar answered Sep 27 '22 18:09

blubb