Python 如何以符合人体工程学的方式迭代具有不同特征的函数
我有一种包含基因的“基因型”。这些基因代表什么并不重要,它们只是任意的对象,都可以被称为“基因对象” 我需要通过几种方法使这个基因突变,但是并不是所有的功能特征都匹配。给定一个起始基因,一个新基因被随机创建,有机会选择其中一种方法(或无方法)进行突变 例如,我有Python 如何以符合人体工程学的方式迭代具有不同特征的函数,python,function,design-patterns,functor,signature,Python,Function,Design Patterns,Functor,Signature,我有一种包含基因的“基因型”。这些基因代表什么并不重要,它们只是任意的对象,都可以被称为“基因对象” 我需要通过几种方法使这个基因突变,但是并不是所有的功能特征都匹配。给定一个起始基因,一个新基因被随机创建,有机会选择其中一种方法(或无方法)进行突变 例如,我有复制(基因),替换(基因,其他基因),插入(基因,其他基因),删除(基因),和其他突变(基因,基因型)。所有这些都返回一个基因列表(即使该列表仅包含一个元素或零个元素),以保持功能特征之间的同质性 我想将这种情况推广到这些变异函数的列表和
复制(基因)
,替换(基因,其他基因)
,插入(基因,其他基因)
,删除(基因)
,和其他突变(基因,基因型)
。所有这些都返回一个基因列表(即使该列表仅包含一个元素或零个元素),以保持功能特征之间的同质性
我想将这种情况推广到这些变异函数的列表和相关的使用概率百分比。我已经有了通过二元搜索和累积分布选择这些基因的方法,我生成了一个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)
会发生什么?或者其他突变(基因、基因型)
需要一个不同但又独立的参数
为了解决这个问题,我想出了几种解决办法。首先,我可以将所有函数签名完全相同。我的意思是,即使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))
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
这里的坚持者是,MutationParameter
的成员不一定都是相互关联的,我们必须事先知道变异签名是什么,您不仅能够添加新签名,还需要更新多个代码部分
另一种处理方法是,我可以使函数参数通用,但这样我将被迫添加一个额外的数据结构,用于处理将数据拉入函数签名的操作(以便所有函数都采用*args
或**kwargs
)这可能意味着为每个签名定制函数,并由于需要将累积概率线性化或与哈希表/字典关联而降低性能
我可以通过生成函子来处理函数,函子将参数的一些数据存储在调用“函数”本身中(例如“其他基因”,比如随机生成基因的生成器)。这需要我为每个函数创建一个新类,以便为每个需要唯一参数的函数处理这种情况。即使这样,我也无法将当前的基因列表,基因型
放入othermutation
,而不在函数本身的执行过程中创建调用时的函数列表(因此并非所有的函数都不能作为mutate
中的突变列表
传入)
不过,如果我想有一个好的方法来处理一个通用的变异列表
,我可能需要咬紧牙关,将需要特定类型信息的一些变异类型与其他类型的变异类型分开,并且我可以只传入两种类型的变异列表
另外,我还可以做一件类似的事情,比如说,将othergene参数作为函子的静态函数/变量,这是所有实例化都会有的
因此,总结三种方法:
变异之前无法确定额外参数的变异函数
我希望避免让我的mutate函数关心底层的突变是什么,这样它就可以尽可能通用。一个合理的策略是用另一个函数包装一个参数的函数,该函数提供但不使用另一个参数:
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
合理的策略是用另一个函数包装一个参数的函数,该函数提供但不使用另一个参数:
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
我看到的问题是:如何知道为每个函数调用提供哪些参数,sinc