Frage

Ich brauche das NetworkX Python-Paket zu erweitern und ein paar Methoden, um die Graph Klasse für meine besondere Notwendigkeit

hinzufügen

So wie ich dachte daran, dies zu tun ist simplying eine neue Klasse sagen NewGraph abzuleiten, und das Hinzufügen der erforderlichen Methoden.

Es gibt jedoch mehrere andere Funktionen in NetworkX die Erstellung und Rückkehr Graph Objekte (zum Beispiel eine Zufallsgraphen erzeugen). Ich brauche jetzt diese Graph Objekte verwandeln sich in NewGraph Objekte, so dass ich meine neue Methoden verwenden können.

Was ist der beste Weg, dies zu tun? Oder soll ich das Problem auf eine ganz andere Art und Weise anpacken?

War es hilfreich?

Lösung

Wenn Sie nur das Verhalten Zugabe werden, und in Abhängigkeit nicht auf zusätzliche Instanz Werten, können Sie auf das __class__ Objekt zuweisen:

from math import pi

class Circle(object):
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return pi * self.radius**2

class CirclePlus(Circle):
    def diameter(self):
        return self.radius*2

    def circumference(self):
        return self.radius*2*pi

c = Circle(10)
print c.radius
print c.area()
print repr(c)

c.__class__ = CirclePlus
print c.diameter()
print c.circumference()
print repr(c)

Prints:

10
314.159265359
<__main__.Circle object at 0x00A0E270>
20
62.8318530718
<__main__.CirclePlus object at 0x00A0E270>

Das ist so nah an einem „Guss“, wie Sie in Python zu bekommen, und wie in C Gießen, ist es nicht ohne dem Thema einige Gedanken zu tun. Ich habe ein ziemlich begrenztes Beispiel geschrieben, aber wenn man in den Grenzen bleiben kann (nur Verhalten hinzufügen, keine neue Instanz VARs), dann könnte dies helfen Adresse Ihres Problem.

Andere Tipps

Hier ist, wie man „magische Weise“ eine Klasse in einem Modul mit einer maßgeschneiderten Unterklasse ersetzen, ohne das Modul zu berühren. Es ist nur ein paar zusätzlichen Zeilen von einem normalen Subklassifizieren Verfahren, und deshalb gibt Ihnen (fast) die ganze Kraft und Flexibilität als Bonus von Subklassen. Zum Beispiel können Sie so neue Attribute hinzufügen, wenn Sie möchten.

import networkx as nx

class NewGraph(nx.Graph):
    def __getattribute__(self, attr):
        "This is just to show off, not needed"
        print "getattribute %s" % (attr,)
        return nx.Graph.__getattribute__(self, attr)

    def __setattr__(self, attr, value):
        "More showing off."
        print "    setattr %s = %r" % (attr, value)
        return nx.Graph.__setattr__(self, attr, value)

    def plot(self):
        "A convenience method"
        import matplotlib.pyplot as plt
        nx.draw(self)
        plt.show()

Bisher ist dies genau wie normale Subklassifizieren. Jetzt müssen wir diese Unterklasse in die networkx Modul anschließen, so dass alle Instanziierung nx.Graph Ergebnisse in einem NewGraph Objekt statt. Hier ist, was normalerweise passiert, wenn Sie ein Objekt nx.Graph mit nx.Graph() instanziiert

1. nx.Graph.__new__(nx.Graph) is called
2. If the returned object is a subclass of nx.Graph, 
   __init__ is called on the object
3. The object is returned as the instance

Wir werden nx.Graph.__new__ ersetzen und es NewGraph stattdessen machen zurückzukehren. Darin wir die __new__ Methode der object anstelle des __new__ Methode der NewGraph nennen, da diese nur eine andere Art von Aufruf der Methode ist sind zu ersetzen wir, und in endlosen Rekursion deshalb führen würde.

def __new__(cls):
    if cls == nx.Graph:
        return object.__new__(NewGraph)
    return object.__new__(cls)

# We substitute the __new__ method of the nx.Graph class
# with our own.     
nx.Graph.__new__ = staticmethod(__new__)

# Test if it works
graph = nx.generators.random_graphs.fast_gnp_random_graph(7, 0.6)
graph.plot()

In den meisten Fällen ist dies alles, was Sie wissen müssen, aber es gibt eine Gotcha. Unser übergeordnetes der __new__ Methode wirkt sich nur auf nx.Graph, nicht ihre Unterklassen. Zum Beispiel, wenn Sie nx.gn_graph nennen, die eine Instanz von nx.DiGraph zurückkehrt, wird es keine unserer Phantasie Erweiterungen haben. Sie müssen jede der Unterklassen von nx.Graph Unterklasse, mit dem Sie arbeiten wollen und Ihre erforderlichen Methoden und Attribute hinzufügen. Mix-ins können erleichtern konsequent die Unterklassen erweitert, während das href="http://en.wikipedia.org/wiki/Don't_repeat_yourself" rel="nofollow noreferrer"> DRY Prinzip

Obwohl dieses Beispiel einfach genug zu sein scheint, diese Methode in einem Modul Einhaken ist schwer, in einer Art und Weise zu verallgemeinern, dass deckt all die kleinen Probleme, die auftauchen können. Ich glaube, es ist einfacher, nur Schneider es auf der Hand, um das Problem. Zum Beispiel, wenn die Klasse Sie sind Einhaken in definiert seine eigene individuelle __new__ Methode, müssen Sie es speichern, bevor sie, und rufen Sie diese Methode anstelle von object.__new__ zu ersetzen.

Wenn eine Funktion schafft Graph-Objekte, können Sie sie nicht in NewGraph drehen Objekte.

Eine weitere Option für NewGraph ist ein Diagramm zu haben, anstatt einen Graph sein. Sie delegieren die Graph Methoden auf das Graph-Objekt Sie haben, und Sie können jede Graph-Objekt in ein neues NewGraph Objekt wickeln:

class NewGraph:
    def __init__(self, graph):
        self.graph = graph

    def some_graph_method(self, *args, **kwargs):
        return self.graph.some_graph_method(*args, **kwargs)
    #.. do this for the other Graph methods you need

    def my_newgraph_method(self):
        ....

Für Ihren einfachen Fall könnten Sie auch Ihre Unterklasse __init__ so schreiben und die Zeiger von den Graph-Datenstrukturen der Unterklasse Daten zuweisen.

from networkx import Graph

class MyGraph(Graph):
    def __init__(self, graph=None, **attr):
        if graph is not None:
            self.graph = graph.graph   # graph attributes
            self.node = graph.node   # node attributes
            self.adj = graph.adj     # adjacency dict
        else:
            self.graph = {}   # empty graph attr dict
            self.node = {}    # empty node attr dict 
            self.adj = {}     # empty adjacency dict

        self.edge = self.adj # alias 
        self.graph.update(attr) # update any command line attributes


if __name__=='__main__':
    import networkx as nx
    R=nx.gnp_random_graph(10,0.4)
    G=MyGraph(R)

Sie können auch copy () oder deep () in den Zuordnungen verwenden, aber wenn Sie tun, dass Sie könnte genauso gut verwenden

G=MyGraph()
G.add_nodes_from(R)
G.add_edges_from(R.edges())

Ihre Diagrammdaten laden.

Sie könnten einfach einen neuen NewGraph erstellen aus Graph Objekt abgeleitet und haben die __init__ Funktion umfasst so etwas wie self.__dict__.update(vars(incoming_graph)) als die erste Zeile, bevor Sie Ihre eigenen Eigenschaften definieren. Auf diese Weise kopieren Sie im Grunde alle die Eigenschaften aus der Graph Sie auf ein neues Objekt haben, von Graph abgeleitet, aber mit Ihrer speziellen Sauce.

class NewGraph(Graph):
  def __init__(self, incoming_graph):
    self.__dict__.update(vars(incoming_graph))

    # rest of my __init__ code, including properties and such

Verbrauch:

graph = function_that_returns_graph()
new_graph = NewGraph(graph)
cool_result = function_that_takes_new_graph(new_graph)

Haben Sie Jungs versucht, [Python] Gussbasisklasse abgeleitete Klasse

Ich habe es getestet und scheint es funktioniert. Ich denke, auch diese Methode ist etwas besser als unter einem da unterhalb einer nicht ausgeführt init Funktion der abgeleiteten Funktion.

c.__class__ = CirclePlus
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top