2016-02-19 1 views
1

J'ai une instance 'graph_main' d'une classe BipartiteGraph que j'ai définie. Tout ce dont j'ai besoin maintenant est de garder cette instance intacte mais de créer une autre instance 'graph1' de cette classe qui est identique à 'graph_main'. Mais pour une raison quelconque, graph_main continue de changer, même si je ne travaille pas du tout. Je suis nouveau à Python, comme deux semaines de neuf. Donc, s'il y a une documentation pertinente que vous pouvez me diriger vers pour apprendre la portée des objets en Python, je vais l'appréprendre.Python: Créer une copie d'une instance d'une classe

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 

Je fournis mon dossier Utils au cas où quelqu'un veut courir et voir mais je doute fortement que serait nécessaire. Je m'attends donc à une sortie de nombre constant de nœuds Bit et Check dans graph_main (c'est une classe de graphes bipartite) pour chaque simulation puisque je ne la change pas. Ici, je suppose graph1 = graph_main crée un nouvel objet identique à l'existant graph_main. Est-ce correct et mon erreur est ailleurs?

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 ** # créer un nouvel objet identique à graph_main? ** 'crée en fait une seconde référence à l'objet auquel' graph_main' fait référence. Ces deux variables pointent maintenant vers le même objet. Vous voudrez faire une méthode '.copy()' ou similaire pour vous permettre de cloner votre objet si vous avez besoin d'une instance séparée. –

+0

Ceci est donc similaire aux pointeurs en C++ où vous affectez le pointeur référençant graph_main à graph1 plutôt que de créer une nouvelle variable comme dans MATLAB .. – mathamateur

+0

Sort-of-but-not-quite. Voir http://robertheaton.com/2014/02/09/pythons-pass-by-object-reference-as-explained-by-philip-k-dick/ pour une explication des différences. En règle générale, chaque opération d'assignation en Python crée une nouvelle référence nommée (le nom de la variable à la recherche d'une chose du côté gauche de l'équation) vers un objet (la chose à droite). Même si 'foo' est déjà défini, dire' foo = bar' remplace l'ancienne * référence * par une nouvelle référence avec le même nom. –

Répondre

1

Utilisez la fonction deepcopy pour créer une instance identique à un nouveau pointeur (par opposition à une copie superficielle, qui est une autre variable pointant vers le même objet).

import copy 

graph1= copy.deepcopy(graph_main) 
+0

Merci. ça fonctionne parfaitement. Mais mes problèmes sont plus profonds que cela, comme l'a souligné Kirk - besoin de comprendre la différence d'affectation et la nouvelle référence nommée, – mathamateur

-1

Je ne suis pas sûr de cela, mais ne pourrais pas vous le faire cela? ...

x = ClassName(arguments, arguments...) 

dup_of_x = x 

Par conséquent, x magasins x et x dup_of_x stocke également