2012-08-02 59 views
5

其實標題並不完全反映我想問的問題。我的目的是這樣的:我正在使用matplotlib編寫一些繪圖函數。我有一系列用於不同繪圖目的的功能。像line_plot()爲線,bar_plot()爲杆等,例如:使用python裝飾器自動替換函數參數的默認值?

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) 

然而問題是,對於已定義的每個功能,我必須重複這部分代碼:

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

有沒有像使用裝飾器的方式,我可以在繪圖函數的定義之前應用它,它會自動執行代碼的重複部分?因此我不必每次重複。

一個可能的選擇是這樣定義一個函數:

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

然後例子如:

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) 

但有沒有更好/清潔/更Python的方式?我想我可以使用裝飾器,但沒有弄清楚。有人可以提出一些想法嗎?

謝謝!

+2

我認爲你最後的解決方案非常好。函數是有效的,經過驗證的構造代碼的方法。我懷疑裝飾者會不必要地使事情複雜化。 – 2012-08-02 08:43:58

+0

也許你可以在你的測試中創建一個軸類,它的init – zenpoy 2012-08-02 09:22:42

回答

7

下面是如何與裝飾做到這一點:

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) 

它是如何工作的:@check_axes語法重新定義了裝飾功能,例如名line_plot是由裝飾者創建的新功能,即_check_axes_wrapped_plot_fn。這個「包裝」功能處理axes - 檢查邏輯,然後調用原始繪圖功能。

如果你想check_axes能夠裝點任何繪圖功能,它接受一個axes作爲第一個參數,而不僅僅是那些還只拿xy參數,你可以使用Python的方便*語法任意參數列表:

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 

現在,這些是否「更好/更清潔/更Pythonic」可能是一個辯論的問題,並取決於更大的背景。順便說一下,本着「更多Pythonic」的精神,我將您的代碼重新格式化爲更接近PEP8風格指南。請注意參數列表中的逗號後面的空格,=賦值運算符周圍的空格(但不是=用於函數關鍵字參數時),並且說not axes而不是axes == None

+1

嗨,感謝Ghopper21的答案。這是我想看到的。是的,它是否更加pythonic應該考慮到更大的圖片。還要感謝代碼的重新格式化,重新格式化的代碼看起來更好:) – wiswit 2012-08-03 12:42:47