2017-04-21 22 views
1

我有一個包含基因排序的「基因型」。這些基因代表的並不重要,它們只是任意可以被稱爲「基因對象」的任意對象。如何符合人體工程學的迭代函數與不同的簽名

我需要這種突變基因,通過多種方法,但函數簽名不是全部匹配。給定一個起始基因,創建一個新的基因,隨機選擇這些方法之一(或沒有方法)進行突變。

例如,我有duplicate(gene)replace(gene, othergene)insert(gene, othergene)delete(gene),和othermutation(gene, genotype)。所有這些都會返回一個基因列表(即使該列表只包含一個元素或零個元素),以便保持函數簽名之間的同質性。

我想這種情況推廣到這些突變的功能列表及相關百分比機會使用。我已經通過二進制搜索和累積分佈選擇這些基因的方法,我產生一個R和可基於來自R.舍入二進制索引檢索正確的功能,這大致可以讓我做到以下幾點:

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 

理想情況下,我不需要知道第五行的突變,我只需要在相關概率的某個位置有一個突變列表。正如你所看到的,replace(gene, othergene)需要第二個參數會發生什麼?或othermutation(gene, genotype)需要一個不同但也是單獨的參數?

爲了解決這個問題,我已經到了多種解決方案。首先,我可以吸收所有功能簽名完全相同。我的意思是,即使duplicate(gene)不需要othergene我仍然會把它放在函數定義中,它只是不會使用它,或者它會做一些微不足道的事情。但是這個解決方案的缺點是每次我需要添加一個帶有新參數的新函數時,我需要更改所有的函數簽名,這違反了SRP類,對於所有函數來說都是這樣,並且會煩人地處理。但是我可以把它作爲一個參數對象來包裝,我在每次迭代中設置需要的參數。如果需要帶有新類型參數的新函數,我可以簡單地將該參數添加到「突變參數」對象中,並將該對象傳遞給每個函數,並且每個函數只會獲得它所需的內容,例如:

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),並且這可能意味着每個簽名的定製函數,並且由於需要將累積概率線性化或關聯到散列表/字典,因此降低了性能。

我可以通過使其中存儲一些用於在調用「功能」本身的參數的數據的函子(如「其它基因」如說發電機,其隨機產生的基因)處理的功能。這需要我爲每個函數創建一個新類,以便處理需要唯一參數的每個函數的這種情況。即使在那時,我也不能說當前的基因列表,genotype轉換成othermutation而在函數本身的執行過程中不會創建函數列表(所以不是所有的函數都不能作爲mutation_listmutate

不過我可能只需要忍辱負重,分離需要某些類型的他人提供的信息,如果我想有處理的通用mutation_list的一個很好的方式有些突變類型,我可以只通過在兩種類型的突變列表

我還可以做一個類似的事情,通過使另一個基因參數成爲函子的靜態函數/變量,所有的實例化都會有。

所以總結了三種方法:

  1. 通所有參數通過參數對象,函數挑選哪些參數,他們需要;

  2. 使用*參數有效地做同樣的事情,但你也需要一個關聯函數爲每個簽名提取數據;

  3. 或者使用函數(帶有或不帶有靜態變量)來保存數據,並使用另一個單獨傳入的突變函數的突變列表,其中調用mutation之前無法確定額外的參數。

我想避免讓我的mutate函數關心底層突變是什麼,這樣它可以是通用的儘可能。

回答

0

我要回答我自己的問題,因爲我發現目前的答案並不令人滿意(幾乎與我的建議答案完全一樣),但已經發現該解決方案對我的具體情況最符合「人體工程學」 (最通用的等,良好的和可擴展的)。

我的第一個建議,

1:通過所有參數通過參數對象,函數挑選和 選擇哪些參數,他們需要

我認爲是對我最好的,甚至可能Python以外的語言和非動態語言。這基本上是這樣的:

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

一個合理的策略是與其他功能用品包裝一個參數的功能,但不使用另一種說法:

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

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

的將兩個短簽名匹配其他功能:replace(gene, othergene), insert(gene, othergene), othermutation(gene, genotype)

另一種策略是使用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,你檢查變量,看看需要什麼樣的參數。您可以正確設置函數調用。將概率與一組函數相關聯,而不是將概率與一組類相關聯。在Python中它們同樣簡單。

相關問題