2012-08-02 10 views
5

En realidad, el título no refleja exactamente la pregunta que quiero formular. Mi propósito es el siguiente: estoy escribiendo algunas funciones de trazado usando matplotlib. Tengo una serie de funciones que son para diferentes propósitos de trazado. como line_plot() para las líneas, bar_plot() para la barra etc., por ejemplo:use el decorador de python para reemplazar automáticamente el valor predeterminado del argumento de función?

import matplotlib.pyplot as plt 
def line_plot(axes=None,x=None,y=None): 
    if axes==None: 
     fig=plt.figure() 
     axes=fig.add_subplot(111) 
    else: 
     pass 
    axes.plot(x,y) 

def bar_plot(axes=None,x=None,y=None): 
    if axes==None: 
     fig=plt.figure() 
     axes=fig.add_subplot(111) 
    else: 
     pass 
    axes.bar(left=x,height=y) 

Sin embargo, el problema es, para cada función que se define, tengo que repetir esta parte del código:

if axes==None: 
     fig=plt.figure() 
     axes=fig.add_subplot(111) 
    else: 
     pass 

¿Hay alguna manera de utilizar un decorador, que puedo aplicar antes de la definición de la función de trazado, que hará la parte repetida del código automáticamente? Por lo tanto, no tengo que repetirlos cada vez.

una opción posible es definir una función como esta:

def check_axes(axes): 
    if axes==None: 
     fig=plt.figure() 
     axes=fig.add_subplot(111) 
     return axes 
    else: 
     return axes 

A continuación, los ejemplos serán como:

import matplotlib.pyplot as plt  
def line_plot(axes=None,x=None,y=None): 
    axes=check_axes(axes) 
    axes.plot(x,y) 

def bar_plot(axes=None,x=None,y=None): 
    axes=check_axes(axes) 
    axes.bar(left=x,height=y) 

Pero ¿Hay una mejor manera/limpia/más Pythonic? Supongo que puedo usar un decorador pero no me di cuenta. ¿Alguien podría dar una idea?

Gracias!

+2

Creo que su última solución es bastante buena. Las funciones son formas eficaces y comprobadas de estructurar el código. Sospecho que un decorador podría complicar las cosas innecesariamente. –

+0

Tal vez puedas crear una clase de ejes con tu prueba en su init – zenpoy

Respuesta

7

Así es como hacerlo con un decorador:

import matplotlib.pyplot as plt  

def check_axes(plot_fn): 
    def _check_axes_wrapped_plot_fn(axes=None, x=None, y=None): 
     if not axes: 
      fig = plt.figure() 
      axes = fig.add_subplot(111) 
      return plot_fn(axes, x, y) 
     else: 
      return plot_fn(axes, x, y) 
    return _check_axes_wrapped_plot_fn 

@check_axes 
def line_plot(axes, x=None, y=None): 
    axes.plot(x, y) 

@check_axes 
def bar_plot(axes, x=None, y=None): 
    axes.bar(left=x, height=y) 

Cómo funciona: la sintaxis @check_axes redefine el nombre de la función de decoración, por ejemplo, line_plot para ser una función nueva creada por el decorador, es decir, _check_axes_wrapped_plot_fn. Esta función "envuelta" maneja la lógica de comprobación axes y luego llama a la función de trazado original.

Si desea check_axes ser capaz de decorar cualquier función trama que lleva un axes como primer argumento, no sólo los que también reciben sólo x y y argumentos, puede utilizar la sintaxis útil * de Python para listas de argumentos arbitrarios:

def check_axes(plot_fn): 
    def _check_axes_wrapped_plot_fn(axes=None, *args): 
     if not axes: 
      fig = plt.figure() 
      axes = fig.add_subplot(111) 
      return plot_fn(axes, *args) # pass all args after axes 
     else: 
      return plot_fn(axes, *args) # pass all args after axes 
    return _check_axes_wrapped_plot_fn 

Ahora, si algo de esto es "mejor/más limpio/más pitónico" es probablemente una cuestión de debate, y depende del contexto más amplio.

Por cierto, en el espíritu de ser "más Pythonic", he reformateado su código para estar más cerca de la guía de estilo PEP8. Observe los espacios después de las comas en las listas de parámetros, los espacios alrededor del operador de asignación = (pero no cuando se usa = para los parámetros de palabra clave de función) y diciendo not axes en lugar de axes == None.

+1

Hola gracias Ghopper21 por tu respuesta. Esto es lo que quiero ver Sí, si es más pitónico debería tener en cuenta la imagen más grande. También gracias por el reformateo del código, y el reformateado se ve mejor :) – wiswit

Cuestiones relacionadas