ProgramingTip

매개 변수가 너무 많은 클래스 : 더 나은 설계 전략?

bestdevel 2020. 11. 11. 20:29
반응형

매개 변수가 너무 많은 클래스 : 더 나은 설계 전략?


저는 뉴런 모델로 작업하고 있습니다. 제가 디자인하고있는 클래스 중 하나는 뉴런의 토폴로지 설명 인 셀 클래스입니다. 많은 변수가 있습니다. 예를 들면 다음과 같습니다.

축삭 분절의 수, 정점 bifibrications, 체세포 길이, 체체 직경, 정점 길이, 분기 임의성, 분기 등 ... 15 개의 매개 변수가 있습니다!

이 모든 것을 배열합니다. 이런 일이 다른 사람들에게 일어나야합니다. 위임 디자인하는 명백한 더 나은 방법이 있습니까, 아니면 제가 옳은 일을하고 있습니까?

업데이트 : 여러분 중가 요청 했듯이이 클래스에는 엄청난 수의 매개 변수 (> 15)가 포함되어 있습니다. 본질적으로 문제는 그들이 만드는 물리적 물리적 현상이 매우 복잡합니다. 이 클래스에서 생성 된 객체의 이미지 표현을 첨부했습니다. 프로그래머가 정의에서 너무 많은 변수를 피하기 위해 다르게할까요?

여기에 이미지 설명 입력

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

이 접근 방식을 시도하십시오.

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))

그런 다음 다음 Neuron과 같이 만들 수 있습니다 .

n = Neuron(apical_bifibrications="special value")

이 접근 방식에는 아무런 문제가 없다고 말하고 싶습니다. 무언가를 모델링하기 위해 15 개의 매개 변수가 필요하다면 15 개의 매개 변수가 필요합니다. 적절한 기본값이 없으면 개체를 만들 때 15 개의 매개 변수를 모두 전달해야합니다. 그렇지 않으면 기본값을 설정하고 나중에 setter를 통해 또는 직접 변경할 수 있습니다.

또 다른 접근 방식은 특정 일반적인 유형의 뉴런 (예시)에 대한 하위 클래스를 만들고 특정 값에 대해 좋은 기본값을 제공하거나 다른 매개 변수에서 값을 파생하는 것입니다.

또는 뉴런의 일부를 별도의 클래스로 캡슐화하고 이러한 부분을 모델링하는 실제 뉴런에 재사용 할 수 있습니다. 즉, 시냅스, 축삭, 소마 등을 모델링하기위한 별도의 클래스를 작성할 수 있습니다.


Python "dict"객체를 사용할 수 있습니까? http://docs.python.org/tutorial/datastructures.html#dictionaries


매개 변수가 너무 많으면 클래스가 너무 많은 일을하고 있음을 나타냅니다.

클래스를 여러 클래스로 나누고 각 클래스는 몇 가지 매개 변수를 사용하는 것이 좋습니다. 이렇게하면 각 클래스가 더 간단하고 많은 매개 변수를 사용하지 않습니다.

코드에 대해 더 많이 알지 못하면 코드를 어떻게 분할해야하는지 정확히 말할 수 없습니다.


작업중인 작업에 대한 예제 코드를 제공 할 수 있습니까? 당신이하는 일에 대한 아이디어를 얻고 더 빨리 도움을받는 것이 도움이 될 것입니다.

클래스에 전달하는 인수가 길어지면 .NET에 모두 넣을 필요가 없습니다 __init__. 클래스를 만든 후 매개 변수를 설정하거나 매개 변수로 가득 찬 사전 / 클래스를 인수로 전달할 수 있습니다.

class MyClass(object):

    def __init__(self, **kwargs):
        arg1 = None
        arg2 = None
        arg3 = None

        for (key, value) in kwargs.iteritems():
            if hasattr(self, key):
                setattr(self, key, value)

if __name__ == "__main__":

    a_class = MyClass()
    a_class.arg1 = "A string"
    a_class.arg2 = 105
    a_class.arg3 = ["List", 100, 50.4]

    b_class = MyClass(arg1 = "Astring", arg2 = 105, arg3 = ["List", 100, 50.4])


당신 같은 외모와 같은 객체 구성하여 인수의 수를 줄일 수 Axon, SomaDendriticTreeLayerV 생성자의 외부, 대신 그 객체를 전달합니다.

매개 변수 중 일부는 예를 들어 구성에만 사용되며 DendriticTree다른 매개 변수는 다른 장소에서도 사용되므로 문제는 명확하지 않지만 확실히 시도해 볼 것입니다.


여러분의 코드를 살펴보고 그 매개 변수가 서로 어떤 관련이 있는지 전혀 모르겠다는 것을 깨달은 후에 (신경 과학 주제에 대한 지식이 부족하기 때문에 혼자서) 객체 지향 설계에 대한 아주 좋은 책을 알려 드리겠습니다. Steven F. Lott의 Object Oriented Design의 Building Skills in Object Oriented Design is a great read and I think you and any other in layout of object-oriented program.

크리에이티브 커먼즈 라이선스에 따라 출시되었으므로 무료로 사용할 수 있습니다. 여기에 PDF 형식의 링크가 있습니다 . http://homepage.mac.com/s_lott/books/oodesign/build-python/latex/BuildingSkillsinOODesign. pdf

나는 당신의 문제가 수업의 전반적인 디자인으로 귀결된다고 생각합니다. 매우 드물지만 초기화를 위해 많은 인수가 필요하며 여기에있는 대부분의 응답에는 다른 초기화 방법이 자세히 설명되어 있지만 많은 경우 클래스를 처리하기 더 쉽고 덜 성가신 클래스로 나눌 수 있습니다. .


이것은 기본 사전을 반복하는 다른 솔루션과 유사하지만 더 간결한 표기법을 사용합니다.

class MyClass(object):

    def __init__(self, **kwargs):
        self.__dict__.update(dict(
            arg1=123,
            arg2=345,
            arg3=678,
        ), **kwargs)

더 자세한 사용 사례를 제공 할 수 있습니까? 프로토 타입 패턴이 작동 할 수 있습니다.

개체 그룹에 유사점이 있다면 프로토 타입 패턴이 도움이 될 수 있습니다. 한 뉴런 집단이 어떤면에서 다른 점을 제외하고는 다른 집단과 똑같은 경우가 많이 있습니까? (즉, 적은 수의 개별 클래스를 갖는 대신 서로 약간 다른 많은 수의 클래스가 있습니다.)

Python은 클래스 기반 언어이지만 Javascript와 같은 프로토 타입 기반 언어로 클래스 기반 프로그래밍을 시뮬레이션 할 수있는 것처럼 클래스에 CLONE 메서드를 제공하여 프로토 타입을 시뮬레이션 할 수 있습니다.이 메서드는 새 객체를 만들고 부모로부터 ivar를 채 웁니다. 전달 된 키워드 매개 변수가 "상속 된"매개 변수를 재정의하도록 clone 메소드를 작성하여 다음과 같이 호출 할 수 있습니다.

new_neuron = old_neuron.clone( branching_length=n1, branching_randomness=r2 )

나는이 상황이나이 주제를 다룰 필요가 없었습니다. 귀하의 설명은 설계를 개발할 때 관련성이있는 추가 클래스가 많이 있음을 알 수 있음을 의미합니다. 구획이 가장 분명합니다. 이것들이 그 자체로 클래스로 등장한다면, 일부 매개 변수가 이러한 추가 클래스의 매개 변수가 될 가능성이 있습니다.


매개 변수에 대한 클래스를 만들 수 있습니다.

여러 매개 변수를 전달하는 대신 하나의 클래스를 전달합니다.


제 생각에, 귀하의 경우 쉬운 해결책은 고차 객체를 매개 변수로 전달하는 것입니다.

예를 들어, 메인 클래스의 여러 인수를 사용 __init__하는가 있습니다 .DendriticTreeLayerV

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
)

이 6 개의 인수를 전달하는 대신 객체를 직접 LayerV전달합니다 DendriticTree(따라서 5 개의 인수를 저장함).

이 값을 어디서나 액세스 할 수 있기를 원할 것이므로 다음을 저장해야합니다 DendriticTree.

class LayerV(__Cell):
    def __init__(self, main_apical_dendrite, ...):
        self.main_apical_dendrite = main_apical_dendrite        

기본값도 갖고 싶다면 다음을 사용할 수 있습니다.

class LayerV(__Cell):
    def __init__(self, main_apical_dendrite=None, ...):
        self.main_apical_dendrite = main_apical_dendrite or DendriticTree()

이런 식으로 DendriticTree고차 클래스에서이 논리를 사용하는 대신 해당 문제에 전념하는 클래스에 기본값이 되어야 하는 것을 위임 합니다 LayerV.

마지막으로 apical_bifibs전달하는 데 사용한에 LayerV액세스해야 할 때을 통해 액세스하십시오 self.main_apical_dendrite.bifibs.

일반적으로 만들고있는 클래스가 여러 클래스의 명확한 구성이 아니더라도 매개 변수를 분할하는 논리적 방법을 찾는 것이 목표입니다. 코드를 깔끔하게 만드는 것뿐만 아니라 대부분 사람들이 이러한 매개 변수가 무엇에 사용되는지 이해하는 데 도움이됩니다. 분할 할 수없는 극단적 인 경우에는 그렇게 많은 매개 변수를 가진 클래스가 있어도 괜찮다고 생각합니다. 인수를 분할하는 명확한 방법이 없다면 아마도 15 개의 인수 목록보다 훨씬 더 명확하지 않은 것으로 끝날 것입니다.

매개 변수를 그룹화하는 클래스를 만드는 것이 과도하다고 생각되면 여기에 표시된collections.namedtuple 대로 기본값을 가질 수있는 것을 간단히 사용할 있습니다 .

참고 URL : https://stackoverflow.com/questions/5899185/class-with-too-many-parameters-better-design-strategy

반응형