在 for 循环中循环 comparing/mutating class 个实例会导致意外行为

Looping over and comparing/mutating class instances in a for loop results in unexpected behavior

我有一个 class 节点,它表示有向图上的一个节点。一个节点包含一个序列(一串字母,在这种情况下是 DNA 的 4 个碱基),以及一个前缀和一个由值 k 定义的后缀,其中前缀是前 k 个字母,后缀是最后 k 个字母顺序。

如果一个节点的后缀与另一个节点的前缀相同,则第一个节点应指向第二个节点,并且一个节点可以指向多个其他节点,但不能指向自己。

我正在从一个文件中按顺序读取,从中创建一个节点列表,并尝试设置列表 "nextNodes",每个节点上的 属性 包含所有它指向的节点。

使用两个嵌套的 for-in 循环遍历节点列表,将每个节点与每个节点进行比较,结果是每个节点的 "nextNodes" 列表包含不应指向的节点。此外,每个节点的列表都是相同的。

我尝试使用 itertools.combinations 方法比较节点,认为问题与 for-in 循环和多重比较有某种关系,但无论哪种方式都会发生相同的行为。我很确定问题发生在 for 循环的执行过程中,但我不知道它是什么...??

这是我的代码 (Python 2.7):

import itertools

class Node():

    def __init__(self, name, seq='', k=3, nextNodes=[]):
        self.name = name
        self.seq = seq
        self.k = k
        self.nextNodes = nextNodes
        if len(seq) > k:
            self.prefix = seq[:k]
            self.suffix = seq[-k:]
        else:
            self.prefix = 'PREFIX'
            self.suffix = 'SUFFIX'

    # ...

    def getSeq(self):
        return self.seq

    def setSeq(self, seq):
        self.seq = seq
        if len(seq) > self.k:
            self.prefix = seq[:self.k]
            self.suffix = seq[-self.k:]

    def getNextNodes(self):
        return self.nextNodes

    def setNextNode(self, node):
        self.nextNodes.append(node)

    def getPrefix(self):
        return self.prefix

    def getSuffix(self):
        return self.suffix

    def __str__(self):
        return self.name

nodes = []
curNode = None
with open('seqs.txt', 'r') as file:
    for line in file:
        if line[0] == '>':
            nodes.append(Node(line[1:].strip('\n')))
            curNode = nodes[-1]
        else:
            curNode.setSeq(curNode.getSeq() + line.strip('\n'))

# When either this for loop or the commented one runs, nextNodes is the
# same for every Node, and contains Nodes that should not be pointed to
for node in nodes:
    for otherNode in nodes:
        if node.getSeq() != otherNode.getSeq() \
        and node.getSuffix() == otherNode.getPrefix():
            node.setNextNode(otherNode)

"""
for node1, node2 in itertools.combinations(nodes, 2):
    if node1.getSeq() != node2.getSeq():
        if node1.getSuffix() == node2.getPrefix():
            node1.setNextNode(node2)
        if node2.getSuffix() == node1.getPrefix():
            node2.setNextNode(node1)
"""

for node in nodes:
    for nextNode in node.getNextNodes():
        print node, '->', nextNode

示例: 如果 'seqs.txt' 是:

>Node 1
AAACCCGGG
>Node 2
GGGTTTCCC
>Node 3
CCCGGGAAA

我们希望节点 1 指向节点 2,节点 2 指向节点 3,节点 3 指向节点 1。但这是输出:

Node 1 -> Node 2
Node 1 -> Node 1
Node 1 -> Node 3
Node 2 -> Node 2
Node 2 -> Node 1
Node 2 -> Node 3
Node 3 -> Node 2
Node 3 -> Node 1
Node 3 -> Node 3

我认为这里的问题是在 Node.js 的构造函数中使用列表作为 nextNodes 的默认值。列表是可变的,因此当您将默认值分配给 self.nextNodes 时,您实际上是在为每个节点分配相同的列表,而不是新列表。然后,当您在任何节点中附加到它时,它们都会得到它,因为它们指向完全相同的列表。实际上,您附加到 self.nextNodes 实际上是在更改默认值。