1

I am attempting to sub-class Graph from the graph_tool package for some graph analysis in Python (so that I can generate some of my own functions, but still use Graph_Tool's functions as well), and I cannot seem to use graph_tool's graph generator methods.

I start by importing my classes:

import graph_tool.all as gt
import numpy.random as np
np.seed(42)

I've tried various versions of the __init__ method:

  1. Build a graph from scratch. This works, but I'd prefer not to use this, because graph_tool has some nice ways to pre-populate your graphs (see 2. and 3. below).

    class myGraph(gt.Graph):
        def __init__(self): 
            super(myGraph, self).__init__()
            self.add_vertex(4)
    
  2. Use graph_tool graph generator methods. This generates a gt.Graph object inside the function. But when I try to print the object outside the function, I get an error.

    class myGraph(gt.Graph):
        def __init__(self):
            self = gt.collection.data['celegansneural']
            print self
    g = myGraph()
    print g
    

The above code returns (note the first line is the result of print self in my `init method):

     <Graph object, directed, with 297 vertices and 2359 edges at 0x1049d2a50> 
     Traceback (most recent call last): <br>
     File "Graph_Tool.py", line 54, in <module> <br>
        print g <br>
      File "/usr/local/lib/python2.7/site-packages/graph_tool/&#95;_init__.py", line 1683, in &#95;_repr__ <br>
        d = "directed" if self.is_directed() else "undirected" <br>
     File "/usr/local/lib/python2.7/site-packages/graph_tool/&#95;_init__.py", line 2412, in is_directed <br>
        return self.__graph.get_directed() <br>
    AttributeError: 'myGraph' object has no attribute '_Graph__graph'
  1. My other approach is to call the parent's __init__ but then override the object with new data. When I do this, everything looks fine as long as I stay in my __init__ method, but once I leave it, my graph is wiped.

    class myGraph(gt.Graph):
        def __init__(self):
            super(myGraph, self).__init__()         
            self = gt.collection.data['celegansneural']
            print self
    g = myGraph()
    print g
    

Which returns the following. Note the first print self returns a populated Graph object, whereas the second print g returns an empty myGraph object

<Graph object, directed, with 297 vertices and 2359 edges at 0x11df610d0>
<myGraph object, directed, with 0 vertices and 0 edges at 0x109d14190>

I apologize in advance if this is some picky problem of graph_tool, library, but I figured that it is more likely my coding error than theirs.

Bakuriu
  • 98,325
  • 22
  • 197
  • 231
Tim
  • 171
  • 2
  • 12
  • 1
    Assigning to `self` doesn't actually change your object in any way. `self` is an ordinary local variable, and variable assignment never mutates objects like that. See http://nedbatchelder.com/text/names.html – user2357112 Feb 20 '17 at 19:51
  • Thank you. That makes sense why 3. isn't working. I am reassigning the local variable "self" within the method to the object, but since __init__ doesn't return "self", I really haven't modified the object that gets returned from the method. – Tim Feb 20 '17 at 19:56

2 Answers2

0

You seem a bit confused about how assignment works in python. But I suppose the correct way to achieve what you want is to call the parent's constructors with the appropriate arguments:

class myGraph(gt.Graph):
    def __init__(self):
        super(myGraph, self).__init__(gt.collection.data['celegansneural'])
g = myGraph()
print(g)
Tiago Peixoto
  • 5,149
  • 2
  • 28
  • 28
  • This is perfect! I didn't notice that `Graph.__init__` accepts a graph object to initialize it. By passing in `gt.collection.data['celegansneural']` to the parents constructor in `myGraph` init, we achieve the effect of creating a `myGraph` that _is_ _a_ `Graph`, and is pre-populated with one of graph-tool's built-in graph generator methods. Thank you! – Tim Feb 21 '17 at 14:20
-1

You should generally prefer composition over inheritance -- unless you want to customize the behavior of the graph class itself, you don't need to subclass gt.Graph, just have one as a member of your own class. Then you can add your own methods to your class, and use the graph's methods when you need to:

class MyGraph(object):
    def __init__(self, graph):
        self.graph = graph

    def do_stuff(self):
        # do stuff with self.graph

# Usage:
my_graph = MyGraph(graph=gt.collection.whatever())
my_graph.do_stuff()
tzaman
  • 46,925
  • 11
  • 90
  • 115
  • I'm not the down voter, but I did uncheck "answer" to change it to Tiago's since his answer achieves the actual intent of inheritance. I get what you're saying about composition, but in this case, `myGraph` _is_ _a_ `Graph` (not `myGraph` _has_ _a_ `Graph`) so composition doesn't fit exactly. Still thank you for your answer. – Tim Feb 21 '17 at 14:15