以计算数学函数的Python函数为例:

def func(x, a, b, c):
    """Return the value of the quadratic function, ax^2 + bx + c."""

    return a*x**2 + b*x + c

假设我想以函数属性的形式"附加"一些进一步的信息.例如,latex 表示法.我知道多亏了PEP232,我可以在函数定义之外做到这一点:

def func(x, a, b, c):
    return a*x**2 + b*x + c
func.latex = r'$ax^2 + bx + c$'

但我想在函数定义本身中进行.如果我写信

def func(x, a, b, c):
    func.latex = r'$ax^2 + bx + c$'
    return a*x**2 + b*x + c

这当然有效,但only after我第一次调用了func(因为Python在执行函数时是"懒惰的")

写一个可调用类是我唯一的 Select 吗?

class MyFunction:
     def __init__(self, func, latex):
         self.func = func
         self.latex = latex

     def __call__(self, *args, **kwargs):
         return self.func(*args, **kwargs)

func = MyFunction(lambda x,a,b,c: a*x**2+b*x+c, r'$ax^2 + bx + c$')

或者,我忽略了语言的一个特点,而没有做到这一点?

推荐答案

实现这一点的更好方法是使用decorator ,为此您有两种 Select :

基于函数的decorator :

您可以创建一个基于函数的decorator ,该decorator 接受latex表示作为参数,并将其附加到它装饰的函数:

def latex_repr(r):
    def wrapper(f):
        f.latex = r
        return f
    return wrapper

然后,您可以在定义函数时使用它,并提供适当的表示:

@latex_repr(r'$ax^2 + bx + c$')
def func(x, a, b, c):
    return a*x**2 + b*x + c

这意味着:

func = latex_repr(r'$ax^2 + bx + c$')(func)

定义latex后,属性立即可用:

print(func.latex)
'$ax^2 + bx + c$'

我已经把这个表示作为一个必要的参数,如果你不想强迫总是给出这个表示,你可以定义一个合理的默认值.

基于类的decorator :

如果类是您的首选项,那么基于类的decorator 也可以以一种比您最初try 的方式更类似的方式来实现类似的效果:

class LatexRepr:
    def __init__(self, r):
        self.latex = r

    def __call__(self, f):
        f.latex = self.latex
        return f

你用同样的方式使用它:

@LatexRepr(r'$ax^2 + bx + c$')
def func(x, a, b, c):
    return a*x**2 + b*x + c

print(func.latex)
'$ax^2 + bx + c$'

这里LatexRepr(r'$ax^2 + bx + c$')初始化类并返回可调用实例(__call__已定义).它的作用是:

func = LatexRepr(r'$ax^2 + bx + c$')(func)
#                   __init__    
#                                  __call__

wrapped做的一样.


因为它们都只是在函数中添加一个参数,所以它们只是按原样返回.他们不会用另一个callable来代替它.

尽管基于类的方法可以做到这一点,但基于函数的decorator 应该更快、更轻量级.


因为Python在执行函数时是"懒惰的":Python只编译函数体,不执行其中的任何语句;它只执行默认参数值(参见著名的Qhere).这就是为什么您首先需要调用函数以"获取"属性latex.

Python-3.x相关问答推荐

Gekko优化超出了方程式的界限(由于某种原因,会产生变量)

无法使用Python slack 螺栓SDK读取在 slack 通道中收到的消息

为什么在Python中使用RANDINT函数时会出现此TypeError?

数据类对象列表的字典获取方法-在数据类列表中查找具有特定变量值的数据类

如何计算累积几何平均数?

我们可以在每个可以使用 Pandas Join 的用例中使用 Pandas merge 吗?

如何获取实例化 `types.GenericAlias` 的下标类?

基于Pandas列动态创建分箱,以使观测值数量或计数占总计数的1%.

隐藏Cartopy中高纬度非矩形投影的右侧轴(纬度)标签

这种类型提示有什么作用?

Python ** 用于负数

Python多进程:运行一个类的多个实例,将所有子进程保留在内存中

合并两个numpy数组

Python 3.10 模式匹配 (PEP 634) - 字符串中的通配符

使用 Sympy 方程进行绘图

为什么在 Python 中不推荐使用 MutableString?

如何将二进制(字符串)转换为浮点值?

TypeError: write() 参数必须是 str,而不是字节(Python 3 vs Python 2)

Python - 类 __hash__ 方法和集合

如何在 Python 3.2 中退出?