Python:创建类实例的副本

11

我有一个名为“graph_main”的BipartiteGraph类的实例,现在我需要保持此实例不变,但创建另一个名为“graph1”的相同类实例,但是因某种原因,当我根本没有使用它时,“graph_main”也会不断地发生变化。我刚学Python,只有几周的经验。如果您可以指向相关文档以了解Python中对象的作用域,我将非常感激。

MWE:

import numpy
import testBipartiteUtils
import random
#These are Bipartite graph parameters
N=30 #No of Bit Nodes
K=10 #No of Check Nodes 
rdeg=2 

graph_main = testBipartiteUtils.BipartGraph([])

for NodeIndex in range(0, K):
    graph_main.addBitNode(NodeIndex)#Adding Bit Node. No edges added

for NodeIndex in range(0, N):
    graph_main.addChkNode(NodeIndex)#Adding Check Node. No edges added

    attachments=random.sample(range(0,K),rdeg) 
    for j in attachments:
        graph_main.addEdge([j,NodeIndex])

for z in range(0,10):
    chan=[]
    for i in range(0,N):
        chan.append(0)

graph1=graph_main **#creating a new object identical to graph_main?**

PeelGraph=testBipartiteUtils.Peeling(graph1,chan)
PeelGraph.zeroStep()
print "graph_main Nodes are-",len(graph_main.BitNodes),len(graph_main.ChkNodes)
print "graph1 Nodes are-",len(graph1.BitNodes),len(graph1.ChkNodes)

del PeelGraph
print "z=",z

我提供了我的Utils文件,以便有人想运行它并查看,但我非常怀疑这是必要的。因此,我期望每次模拟在graph_main(它是一个二分图类)中具有恒定数量的Bit和Check节点输出,因为我没有更改它。在这里,我假设graph1 = graph_main创建了一个与现有graph_main相同的新对象。这是正确的吗?我的错误在其他地方吗?

testBipartiteUtils.py

import numpy

 class Edge:

 def __init__(self, n1, n2):
    """Constructor. Takes bit and check node IDs as arguments"""
    self.node1=n1
    self.node2=n2

def getNodes(self):
    """Returns a list containing the bit and check nodes for this edge"""
    return [self.node1, self.node2]

def hasNodes(self, n1, n2):
    """Takes two node IDs. Returns true if the IDs match the two nodes of this edge in that order."""
    if(self.node1==n1 and self.node2==n2):
        return True

    return False


 class BitNode:
""" Basic node class."""

def __init__(self, name):
    """Constructor. Takes a node ID"""
    self.ID=name
    self.neighbors=[]
    self.degree= 0

def addNeighbors(self, nbs):
    """Adds a list of neighbors to the current list. Takes a list of node IDs"""
    for i in range(0, len(nbs)):
        if(not nbs[i] in self.neighbors):
            self.neighbors.append(nbs[i])
            self.degree+=1

def getID(self):
    """Returns node ID"""
    return self.ID

def getNeighbors(self):
    """Returns list of neighbor IDs"""
    return self.neighbors


 class ChkNode:

def __init__(self, name):
    """Constructor. Takes a node ID"""
    self.ID=name
    self.neighbors=[]
    self.chan = int(-1)
    self.degree= 0


def addNeighbors(self, nbs):
    """Adds a list of neighbors to the current list. Takes a list of node IDs"""
    for i in range(0, len(nbs)):
        if(not nbs[i] in self.neighbors):
            self.neighbors.append(nbs[i])
            self.degree+=1

def getID(self):
    """Returns node ID"""
    return self.ID

def getNeighbors(self):
    """Returns list of neighbor IDs"""
    return self.neighbors


 class BipartGraph:
def __init__(self, eds):
    """Constructor. Takes a list of edge primitives, which is a list of two node IDs.
    Iterates through the edges, creates nodes for unique node IDs, and adds all edges and nodes.
    """
    self.size = 0
    self.BitNodes = []
    self.ChkNodes = []
    self.edges = []
    for i in range(0, len(eds)):
        self.addEdge(eds[i])


def containsEdge(self, edgep):
    """Checks for an edge in the graph. Takes an edge primitive, which is a list of two node IDs. First ID is bit node, second ID is of Check node"""
    for e in self.edges:
        if(e.hasNodes(edgep[0], edgep[1])):
            return True


def getBitNode(self, name):
    """Checks if a given Bit Node ID exists in the graph. If not, it creates and adds a Bit Node for the given ID. Returns the Bit Node"""
    for i in range(0, len(self.BitNodes)):
        if(self.BitNodes[i].getID()==name):
            return self.BitNodes[i]
    newNode = BitNode(name)
    self.BitNodes.append(newNode)
    return self.BitNodes[len(self.BitNodes)-1]

def getChkNode(self, name):
    """Checks if a given Chk Node ID exists in the graph. If not, it creates and adds a Chk Node for the given ID. Returns the Chk Node"""
    for i in range(0, len(self.ChkNodes)):
        if(self.ChkNodes[i].getID()==name):
            return self.ChkNodes[i]
    newNode = ChkNode(name)
    self.ChkNodes.append(newNode)
    return self.ChkNodes[len(self.ChkNodes)-1]

def getEdges(self):
    """Returns list of edges"""
    return self.edges

def addBitNode(self, name):
    """Adds a Bit node, based on Bit node ID"""
    newNode = BitNode(name)
    self.BitNodes.append(newNode)

def addChkNode(self, name):
    """Adds a Check node, based on node ID"""
    newNode = ChkNode(name)
    self.ChkNodes.append(newNode)

def addEdge(self, edgep):
    """Adds an edge into the graph, and updates neighbors & degrees of relevant nodes.
    Takes an edge primitive, a list of two node IDs
    """
    if(not self.containsEdge(edgep)):
        no1 = self.getBitNode(edgep[0])
        no2 = self.getChkNode(edgep[1])
        newEdge = Edge(edgep[0], edgep[1])
        self.edges.append(newEdge)
        no1.addNeighbors([no2.getID()])
        no2.addNeighbors([no1.getID()])

 class Peeling:
"""peeling decoder on a Bipartite graph class.
"""
def __init__(self, G,chan):
    """Constructor. Takes a graph and channel output vector as arguments"""
    self.graph=G
    for i in range(0,len(self.graph.ChkNodes)):
        self.graph.ChkNodes[i].chan=chan[i]
    self.deg1Chks=[]

def zeroStep(self):
    self.graph.BitNodes.pop(0)

def peelIter(self):
    self.graph.ChkNodes.pop(0)

1
graph1=graph_main **#creating a new object identical to graph_main?** 实际上是创建了一个指向graph_main所引用的对象的第二个引用。现在这两个变量都指向同一个对象。如果你需要一个单独的实例,你需要编写 .copy() 方法或类似方法来允许你克隆你的对象。 - Kirk Strauser
所以这类似于C++中的指针,通过将指向graph_main的指针分配给graph1,而不是像MATLAB中那样创建一个新变量。 - mathamateur
1
有点但并不完全一样。请查看http://robertheaton.com/2014/02/09/pythons-pass-by-object-reference-as-explained-by-philip-k-dick/了解其差异的解释。作为一个经验法则,在Python中的每个赋值操作都会创建一个新的命名引用(等式左边看起来像变量名的东西)指向一个对象(右侧的那个东西)。即使“foo”已经被定义,说“foo = bar”也会用相同名称创建新的引用取代旧的引用 - Kirk Strauser
谢谢。我觉得我理解了,但是如果我暂时不用Python,再回来看的话,我可能会感到困惑。你能给我指一些其他详细解释这个东西的资料吗? - mathamateur
2个回答

17

使用deepcopy函数创建一个全新指针的相同实例(与浅复制不同,浅复制只是另一个指向同一对象的变量)。

import copy

graph1= copy.deepcopy(graph_main)

谢谢。那个完美地解决了我的问题。但正如 Kirk 指出的那样,我的问题比这更深层次,需要理解赋值和新命名引用的区别。 - mathamateur

-7

我不确定,但你难道不能这样做吗?...

x = ClassName(arguments, arguments...)

dup_of_x = x

因此,x 存储 x,dup_of_x 也存储 x


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接