生成器方法、深拷贝与浅拷贝

1 投票
1 回答
1932 浏览
提问于 2025-04-16 19:49

我正在尝试在一个自定义类(图类)中避免使用深拷贝(deepcopy)。

这个图类有一些属性,比如顶点、边等等,还有几个生成器方法(带有yield的函数)。

我需要复制这个图,比如说用H = deepcopy(G),但我不想用深拷贝,因为这样会让程序变慢。

那么:

  • 如果我不使用deepcopy,那么新图H中的生成器方法就无法获取图G中生成器方法的当前状态。

  • 如果我不使用生成器方法,而选择使用完整的列表生成器,那么我就会浪费计算时间,做一些没有用的事情。

我的解决方案是尝试对一些特定的生成器方法进行深拷贝,但我遇到了错误。

看起来这些生成器保存了对图G的顶点和边的引用,然后当我把它们深拷贝到H时,H中的生成器仍然引用着G的属性(这听起来很合理)。

所以,我是不是注定要使用deepcopy,或者根本不使用生成器方法呢?

有没有第三种更符合Python风格的方法呢?

1 个回答

2

我觉得我明白你想表达的意思。这里有一个简单的例子:

class Graph:
    def __init__(self, nodes):
        self.nodes = list(nodes)
        self.nodegen = self.iternodes()
    def iternodes(self):
        for node in self.nodes:
            yield node
    def copy(self):
        return Graph(self.nodes)

G = Graph([1, 2, 3, 4])
print G.nodegen.next()
H = G.copy()
print H.nodegen.next()
print G.nodegen.next()

当然,这段代码会打印出 1 1 2。不过,你希望 H.nodegen 能记住 G.nodegen 的状态,这样当你调用 H.nodegen.next() 时就能打印出 2。一个简单的方法是让它们成为同一个对象:

class Graph:
    def __init__(self, nodes, nodegen=None):
        self.nodes = list(nodes)
        self.nodegen = self.iternodes() if nodegen is None else nodegen
    def iternodes(self):
        for node in self.nodes:
            yield node
    def copy(self):
        return Graph(self.nodes, self.nodegen)

这样就会打印出 1 2 3,因为调用 H.nodegen.next() 时也会让 G.nodegen 向前移动。如果这不是你想要的,那么我觉得可以保持一个内部计数器,像这样:

class Graph:
    def __init__(self, nodes, jnode=0):
        self.nodes = list(nodes)
        self.nodegen = self.iternodes()
        self.jnode = jnode
    def iternodes(self):
        while self.jnode < len(self.nodes):
            self.jnode += 1
            yield self.nodes[self.jnode-1]
    def copy(self):
        return Graph(self.nodes, self.jnode)

这样会打印出 1 2 2,我猜这就是你想要的。当然,当你改变 self.nodes 时,你需要处理一些事情,比如使迭代器失效,但我觉得这应该相对简单。

撰写回答