使用python decorator自动替换函数参数默认值?

wis*_*wit 6 python arguments function decorator

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

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)
Run Code Online (Sandbox Code Playgroud)

然而问题是,对于定义的每个函数,我必须重复这部分代码:

    if axes==None:
        fig=plt.figure()
        axes=fig.add_subplot(111)
    else:
        pass
Run Code Online (Sandbox Code Playgroud)

有没有办法像使用装饰器,我可以在绘图功能的定义之前应用,它会自动执行代码的重复部分?因此,我不必每次都重复它们.

一个可能的选择是定义一个这样的函数:

def check_axes(axes):
    if axes==None:
        fig=plt.figure()
        axes=fig.add_subplot(111)
        return axes
    else:
        return axes
Run Code Online (Sandbox Code Playgroud)

那么例子就像:

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)
Run Code Online (Sandbox Code Playgroud)

但是有更好/更干净/更pythonic的方式吗?我想我可以使用装饰器,但没有想出来.任何人都可以提出一些想法?

谢谢!!

Gho*_*r21 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)
Run Code Online (Sandbox Code Playgroud)

工作原理:@check_axes语法重新定义了修饰函数的名称,例如line_plot,是由装饰器创建的新函数,即_check_axes_wrapped_plot_fn.这个"包装"函数处理axes-checking逻辑,然后调用原始的plot函数.

如果你希望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  
Run Code Online (Sandbox Code Playgroud)

现在,无论这些是"更好/更清洁/更多Pythonic"可能是一个争论的问题,并取决于更大的背景.

顺便说一下,本着"更多Pythonic"的精神,我重新格式化了你的代码,使其更接近PEP8风格指南.注意参数列表中逗号后面的空格,=赋值运算符周围的空格(但不是=用于函数关键字参数时),not axes而是代替axes == None.