para numerica introduccion integrales graficar diferenciacion derivadas derivada definidas con calculo algoritmo python inheritance derived-class base-class

numerica - Lanza la clase base a la clase de python derivada(o forma más pitonica de extender clases)



introduccion al calculo con python (6)

¿Han intentado [Python] lanzar la clase base a la clase derivada

Lo he probado y parece que funciona. También creo que este método es un poco mejor que uno inferior, ya que debajo uno no ejecuta la función init de la función derivada.

c.__class__ = CirclePlus

Necesito extender el paquete de python Networkx y agregar algunos métodos a la clase Graph para mi necesidad particular

La forma en que pensé hacer esto es simplemente derivar una nueva clase, decir NewGraph , y agregar los métodos necesarios.

Sin embargo, hay otras funciones en networkx que crean y devuelven objetos Graph (por ejemplo, generar un gráfico aleatorio). Ahora necesito convertir estos objetos Graph en objetos NewGraph para poder usar mis nuevos métodos.

Cual es la mejor manera de hacer esto? ¿O debería abordar el problema de una manera completamente diferente?


Aquí se explica cómo reemplazar "mágicamente" una clase en un módulo con una subclase hecha a medida sin tocar el módulo. Son solo unas pocas líneas extra de un procedimiento de subclases normal, y por lo tanto te da (casi) todo el poder y la flexibilidad de la subclasificación como bonificación. Por ejemplo, esto le permite agregar nuevos atributos, si lo desea.

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()

Hasta ahora, esto es exactamente como una subclasificación normal. Ahora tenemos que enganchar esta subclase en el módulo networkx para que todas las instancias de nx.Graph en un objeto NewGraph . nx.Graph es lo que normalmente sucede cuando nx.Graph una instancia de un objeto nx.Graph() con nx.Graph()

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

Reemplazaremos nx.Graph.__new__ y lo haremos regresar NewGraph en NewGraph lugar. En él, llamamos al método __new__ de object lugar del método __new__ de NewGraph , porque este último es simplemente otra forma de llamar al método que estamos reemplazando, y por lo tanto daría como resultado una recursión sin fin.

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()

En la mayoría de los casos, esto es todo lo que necesita saber, pero hay un gotcha. Nuestra anulación del método __new__ solo afecta nx.Graph , no sus subclases. Por ejemplo, si llama a nx.gn_graph , que devuelve una instancia de nx.DiGraph , no tendrá ninguna de nuestras extensiones de lujo. nx.Graph subclasificar cada una de las subclases de nx.Graph que desea trabajar y agregar los métodos y atributos necesarios. El uso de mix-ins puede hacer que sea más fácil extender consistentemente las subclases mientras se obedece el principio DRY .

Aunque este ejemplo puede parecer bastante directo, este método de enganche en un módulo es difícil de generalizar de una manera que cubra todos los pequeños problemas que puedan surgir. Creo que es más fácil adaptarlo al problema en cuestión. Por ejemplo, si la clase en la que está enganchando define su propio método __new__ personalizado, debe almacenarlo antes de reemplazarlo y llamar a este método en lugar del object.__new__ .


Para su caso simple también podría escribir su subclase __init__ esta manera y asignar los punteros desde las estructuras de datos de Graph a sus datos de subclase.

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)

También podría usar copy () o deepcopy () en las asignaciones, pero si lo hace, también podría usar

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

para cargar su información gráfica


Si solo está agregando comportamiento y no depende de valores de instancia adicionales, puede asignarle al objeto __class__ :

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)

Huellas dactilares:

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

Esto es lo más parecido a un "elenco" que se puede obtener en Python, y como en C, no se puede hacer sin pensarlo un poco. He publicado un ejemplo bastante limitado, pero si puedes mantenerte dentro de las restricciones (solo agrega comportamiento, no nuevos vars de instancia), entonces esto podría ayudar a resolver tu problema.


Si una función está creando objetos Graph, no puede convertirlos en objetos NewGraph.

Otra opción es que NewGraph tenga un gráfico en lugar de ser un gráfico. Delega los métodos Graph al objeto Graph que tiene, y puede envolver cualquier objeto Graph en un nuevo objeto NewGraph:

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): ....


Simplemente podría crear un nuevo NewGraph derivado del objeto Graph y hacer que la función __init__ incluya algo como self.__dict__.update(vars(incoming_graph)) como primera línea, antes de definir sus propias propiedades. De esta forma, básicamente copia todas las propiedades del Graph que tiene sobre un nuevo objeto, derivado de Graph , pero con su salsa especial.

class NewGraph(Graph): def __init__(self, incoming_graph): self.__dict__.update(vars(incoming_graph)) # rest of my __init__ code, including properties and such

Uso:

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