2017-04-21 7 views
1

유전자가 들어있는 "유전자형"이 있습니다. 그 유전자가 나타내는 것은 중요하지 않으며, 그들은 모두 "유전자 객체"로 참조 될 수있는 임의의 객체입니다.인체 공학적으로 다른 서명으로 함수를 반복하는 방법

여러 가지 방법으로이 유전자를 변이시킬 필요가 있지만 모든 기능 서명이 일치하는 것은 아닙니다. 시작 유전자가 주어지면, 돌연변이에 대해 이러한 방법 중 하나를 선택하거나 무작위로 선택할 수있는 새로운 유전자가 생성됩니다.

예를 들어, 나는 duplicate(gene), replace(gene, othergene), insert(gene, othergene), delete(gene)othermutation(gene, genotype) 있습니다. 함수 서명 간의 동질성을 유지하기 위해 목록의 모든 요소는 목록에 하나의 요소 만 포함하거나 0 개의 요소 만 포함하여 반환됩니다.

나는 이러한 돌연변이 함수의 목록과 관련된 백분율 기회를 일반화하고자한다.

def mutate(genotype, mutation_list, cumulative_probabilities) 
    mutated_genotype = [] 
    for gene in genotype: 
     r = random.random() 
     mutation = mutation_list(cumulative_probabilities(r)) 
     mutated_genotype.extend(mutation(gene)) 
    return mutated_genotype 

: 이미 이진 검색 누적 분포 통해이 유전자를 선택하는 방법을, I는 R을 생성 R.에서 둥근 이진 지수에 기초하여 적절한 기능을 검색 할 수있는이 대략 저 다음을 수행 할 수 있도록 이상적으로 나는 다섯 번째 라인에서 돌연변이를 알아야 할 필요가 없습니다. 단지 돌연변이리스트를 관련 가능성이있는 어딘가에 배치해야합니다. 보시다시피 두 번째 매개 변수가 필요한 replace(gene, othergene)은 어떻게됩니까? 아니면 othermutation(gene, genotype) 다른 별도의 매개 변수가 필요합니까?

이 문제를 해결하기 위해 몇 가지 해결책을 찾아 냈습니다. 첫째, 나는 모든 기능 서명을 정확히 동화시킬 수 있습니다. 이것에 의해 의미하는 것은 비록 duplicate(gene)othergene을 필요로하지 않더라도 나는 그것을 여전히 함수 정의에 넣을 것이다. 단지 그것을 사용하지 않거나 그것과 함께 사소한 것을 할 것이다. 그러나이 솔루션의 단점은 새로운 매개 변수를 사용하여 새 함수를 추가해야 할 때마다 모든 함수 시그니처를 변경해야한다는 것입니다. 모든 함수 시그니처는 모든 함수에 대해 일종의 클래스로 SRP를 위반하며이를 처리하는 데 짜증이납니다. . 하지만 각 반복에서 필요한 매개 변수를 설정하는 하나의 매개 변수 개체로 래핑 할 수 있습니다. 새로운 타입의 인자를 가진 새로운 함수가 필요하다면, 간단히 그 인자를 "mutation parameter"객체에 추가하고,이 객체를 모든 함수에 전달할 수 있습니다. 그리고 모든 함수는 필요한 것만 얻습니다. 예를 들면 :

for gene in genotype: 
    #note other gene is created from some other function or is a generator itself 
    mutation_parameter = MutationParameter(gene, genotype, othergene) 
    r = random.random() 
    mutation = mutation_list(cumulative_probabilities(r)) 
    mutated_genotype.extend(mutation(mutation_parameter)) 

여기에 까다로운 사람은 MutationParameter의 구성원들이 서로 관련된 모든 것은 아니다 우리가 돌연변이 서명이 손 전에 무엇인지, 당신은 단지를 추가 할 수 없습니다에 대해 알고해야한다는 것입니다 새로운 서명, 코드의 여러 섹션을 업데이트해야합니다.

내가 처리 할 수있는 또 다른 방법은 함수 매개 변수를 일반화 할 수 있지만이 방법으로 함수 서명에 데이터를 가져 오는 처리를 담당하는 추가 데이터 구조를 추가해야합니다 (모든 함수가 *args이되도록). 또는 **kwargs) 이는 가능한 경우 누적 확률을 해시 테이블/사전과 선형화하거나 연관시켜야하기 때문에 각 서명에 대한 맞춤 함수와 성능 저하를 의미합니다.

저는 '함수'호출에서 매개 변수에 대한 데이터 중 일부를 저장하는 펑터 (예 : 유전자를 무작위로 생성하는 생성기와 같은 "다른 유전자")를 만들어 함수를 처리 할 수 ​​있습니다. 고유 매개 변수가 필요한 각 함수에 대해이 상황을 처리하기 위해 각 함수에 대해 새 클래스를 작성해야합니다.그럼에도 불구하고 현재 유전자리스트 인 genotypeothermutation에 넣지 않고 함수 자체를 실행하는 동안 호출 할 때 함수 목록을 만들지 않았습니다. (모든 펑터가 mutate에서 mutation_list. 아직

난 그냥 비트에 총알이 나는 일반적인 mutation_list 처리의 좋은 방법이하려는 경우 다른 사람의 특정 유형의 정보를 필요로하는 일부 돌연변이 유형을 분리하고 난 그냥 통과 할 수 있습니다 두 가지 유형의 돌연변이 목록

나는 othergene 매개 변수를 정적 함수/변수를 펑터에 추가하여 인스턴스화를 모두 수행함으로써 유사한 작업을 추가로 수행 할 수 있습니다. 가지고있다. 그래서

는 세 가지 방법 요약 : 파라미터 객체를 통해, 기능 선택에서

  1. 패스 모든 매개 변수를하고 그들이 필요로하는 매개 변수를 선택할;

  2. * args를 사용하면 효과적으로 동일한 작업을 수행 할 수 있지만 데이터를 추출하기 위해 각 서명에 대한 관련 함수가 필요합니다.

  3. mutation이 호출되기 전에 추가 매개 변수를 결정할 수없는 돌연변이 함수에 대해 돌연변이 목록에 전달 된 다른 분리 된 문자로 데이터를 보유하는 펑터 (정적 변수가 있거나없는 경우)를 사용하십시오.

내 변형 기능을 사용하여 기본 돌연변이가 무엇인지 신경 쓰지 않으려 고 가능한 한 일반화 할 수 있습니다.

답변

0

저는 현재의 대답이 만족스럽지 않고 (거의 제 제안 된 대답과 거의 동일 함) 발견했기 때문에 제 자신의 질문에 답할 것입니다.하지만이 솔루션이 제 특정한 상황에 가장 인간 공학적이라는 것을 알았습니다 (가장 일반적인 등, 잘 형성되고 확장 가능).

나의 첫번째 제안,

1 : 파라미터 객체를 통해, 기능 선택에서 모든 매개 변수를 전달하고 들이

이 필요한 매개 변수를 선택 나는 어쩌면, 나에게 가장 좋은 것으로 판명 파이썬 외부와 비 동적 언어로. 기본적으로 다음과 같습니다.

class MutationParameters: 
    def __init__(self, param1, param2, param3 ...): 
     self.param1 = param1 
     self.param2 = param2 
     self.param3 = param3 
     ... 

def mutate(genes, mutator_generator, otherparams...): 
    # paraminit... 
    new_genes = [] 
    mutation_params = MutationParameters(param1, param2, param3...) 
    for gene in genes: 
     # runtime param init ... 
     mutation_params.paramn = paramn #runtime param 
     new_genes = next(mutator_generator)(mutation_params) 
     new_genes.extend(new_genes) 
    return StackGenotype(new_genes) 

새 매개 변수가 필요한 경우? MutationParameters를 업데이트하고, mutate를 한 번 업데이트합니다. 다른 모든 함수의 매개 변수를 변경할 필요가 없습니다 (따라서 매개 변수를 사용하는 이유와 일부를 무시하는 것이 좋은 생각이 아닙니다. 펑터와 유사합니다). 새 함수를 추가 하시겠습니까? 하나의 변수 만 필요로하고 내부에서 필요한 매개 변수를 찾으십시오. 이것은 C++에서도 작동합니다.

어떤 사람이 더 좋은 대답을 게시하지 않는 한 이것이 내 문제의 최선의 해결책이 아니라면 더 나은 대답이 나올 때까지 대답으로 표시하겠습니다.

0

합리적인 전략은 공급 다른 기능을 하나 개의 인자의 기능을 래핑하는 것입니다 그러나 다른 인수를 사용하지 않습니다 replace(gene, othergene), insert(gene, othergene), othermutation(gene, genotype)을 :

def dup2(gene, othergene): 
    return duplicate(gene) 

def del2(gene, othergene): 
    return delete(gene) 

(가) 두 개의 짧은 서명이 다른 기능과 일치 할 것입니다.

또 다른 전략은 가능성을 테스트하기 위해 try/except을 사용하는 것입니다

try: 
    return func(gene, othergene)  # try two-arguments 
except TypeError: 
    return func(gene)    # try one-argument 
0

내가 볼 문제는 : 그들은 동일한 서명을 가지고 있지 않기 때문에 어떻게, 각 함수 호출을 제공하기 위해 어떤 매개 변수를 알 수 있습니까 ? 필자는 필요없는 인수를 피하고 이해하기 쉬운 방식으로 프로그램을 구성하는 좋은 방법이 있다고 생각합니다. 간단한 함수 대신 클래스를 사용하십시오. 클래스는 작업 함수에서 필요한 인수의 수와 유형을 확인할 수있는 방법을 제공합니다. 이 코드를 기본 클래스로 계수 할 수 있습니다. 예를 들어 :

class MutatorBase: 
    def __init__(self, needs_othergene=False, needs_genotype=False): 
     self.needs_othergene = needs_othergene 
     self.needs_genotype = needs_genotype 

    def f(self, gene, othergene=None, genotype=None): 
     """This is the function that does the actual calculations""" 
     raise NotImplementedError 

지금 당신은 당신이 실제 기능 f을 구현하는 파생 클래스의 무리를합니다. 생성자에서는 변수 needs_othergeneneeds_genotype을 설정합니다. 예 :

class Duplicator(MutatorBase): 
    def __init__(self): 
     super().__init__() 

    def f(self, gene): 
     return duplicate(gene) 

class Replacer(MutatorBase): 
    def __init__(self): 
     super().__init__(needs_othergene=True) 

    def f(self, gene, othergene=g): 
     return replace(gene, g) 

당신이 이들 중 하나를 호출하기 전에, 당신이 필요한 인자의 종류를 확인하기 위해 변수를 확인,이 replacer.f 이름을 말할. 함수 호출을 적절하게 설정합니다. 확률을 함수 집합과 연결하는 대신 확률을 클래스 집합과 연관시킵니다. 파이썬에서도 똑같이 쉽게 사용할 수 있습니다.