8

实际上标题并不能完全反映我想问的问题。我的目的是这样的:我正在使用 matplotlib 编写一些绘图函数。我有一系列用于不同绘图目的的功能。比如 line_plot() 用于线条, bar_plot() 用于条形等,例如:

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)

但是有更好/干净/更蟒蛇的方式吗?我想我可以使用装饰器,但没有弄清楚。有人可以给出一些想法吗?

谢谢!!

4

1 回答 1

6

以下是使用装饰器的方法:

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能够装饰任何将 aaxes作为其第一个参数的绘图函数,而不仅仅是那些也仅接受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.

于 2012-08-02T12:17:40.163 回答