如何在递归中生成 class 的新实例

How to generate a new instance of a class in recursion

最近在学习序列比对算法。得到对齐矩阵后,我可以找到一个最优路径,但是我在寻找多个最优路径(回溯)时遇到了麻烦!

我的想法是用多个实例存储多条路径的结果,最后循环遍历基class的所有实例得到答案。 我知道以下条件:

  1. 什么条件退出递归
  2. 什么时候需要创建新实例,什么时候不需要创建?

但是问题出在第二种情况。不知道有多少最优结果,也不知道会产生多少新实例

所以我希望能够动态生成一个带有变量的实例名。

我不知道怎么做:

# those equivalent to new_instance_name = ResultSeq()
a="new_instance_name"
create_new_instance(a,ResultSeq)

我的结果基class是ResultSeq:

class KeepRefs(object):
    """
    reference:
    """
    __refs__ = defaultdict(list)

    def __init__(self):
        self.__refs__[self.__class__].append(weakref.ref(self))

    @classmethod
    def get_instances(cls):
        for inst_ref in cls.__refs__[cls]:
            inst = inst_ref()
            if inst is not None:
                yield inst


class ResultSeq(KeepRefs):
    """
    save two
    """
    def __init__(self, seq1="", seq2=""):
        super(ResultSeq, self).__init__()
        self.seq1 = seq1
        self.seq2 = seq2

下面是我的递归代码:

def multi_backtracking(self, array, i, j, result_seq):
    """
    :param array: V, E, F
    :param i: row
    :param j: col
    :param result_seq: new instance of the class ResultSeq
    :return: Multiple alignment results
    """

    def create_new_obj(name, obj):
        """
        I don't know how to do this.
        """
        pass

    if i == 0 and j == 0:
        pass
    else:
        if array is self.array_V:
            if sum(pass_judgement) == 1:
                """
                An optimal path without creating a new instance.
                """
                self.multi_backtracking(self.array_V, i, j, result_seq)
            else:
                """
                Multiple paths, need to create a new instance
                """
                new_instance_name = "xxx"
                create_new_obj(new_instance_name, ResultSeq)
                ...
                if pass_judgement[0]:
                    result_seq.seq1 = self.origin_seq.seq1[i - 1] + result_seq.seq1
                    result_seq.seq2 = self.origin_seq.seq2[j - 1] + result_seq.seq2
                    self.multi_backtracking(self.array_V, i - 1, j - 1, new_instance_name)
                if pass_judgement[1]:
                    self.multi_backtracking(self.array_E, i, j, new_instance_name)
                if pass_judgement[2]:
                    self.multi_backtracking(self.array_F, i, j, new_instance_name)

这只是我的解决方案之一。如果有更好的建议,我会很乐意采纳,谢谢!

您不需要 names 来存储变量 - 您可以使用一个简单的列表来存储您的实例:

class A:
    def __init__(self,value):
        self.value = value
    def __repr__(self):
        return f" _{self.value}_ "

def rec(i):
    """Recursive function, returns a list of instances of class A with decreasing
    value i""" 
    if i < 0:
        return []

    return [A(i)] + rec(i-1) 

k = rec(5)
print(k)

输出:

[ _5_ ,  _4_ ,  _3_ ,  _2_ ,  _1_ ,  _0_ ]

您可以通过索引访问列表中的实例:

print(k[2])   # _3_

print(k[2].value + k[3].value)  # 5

如果您真的需要 名称,您可以使用字典来存储它们——这与您现有的基类 KeepRefs 所做的大致相同 (*):

data = { "Instance1" : A(42), "Instance2" : A(3.141)}

print(data) 
print( data["Instance1"].value + data["Instance2"].value )

输出:

{'Instance1':  _42_ , 'Instance2':  _3.141_ }
45.141

大多数时候,当您需要用户生成 "names" 变量时,您应该非常强烈地重新考虑您的选择。


(*) 您的基类不会保留 non-referenced 个实例,真正的字典会阻止垃圾收集:

k1 = ResultSeq("A","B")
k2 = ResultSeq("C","D")
k3 = ResultSeq("E","F")

for g in ResultSeq.get_instances():
    print(g.seq1, g.seq2)

k2 = None # no instance of k2 anywhere
k3 = None # no instance of k3 anywhere

对于 ResultSeq.get_instances() 中的 g: 打印(g.seq1,g.seq2)

A B
C D
E F

A B # 2.print loop after removing instances k2,k3

文档:

https://docs.python.org/3/library/weakref.html