xnx*_*xnx 20 python function introspection python-3.x
以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
Run Code Online (Sandbox Code Playgroud)
假设我想以函数属性的形式"附加"一些其他信息.例如,LaTeX表示.我知道,由于PEP232,我可以在函数定义之外执行此操作:
def func(x, a, b, c):
return a*x**2 + b*x + c
func.latex = r'$ax^2 + bx + c$'
Run Code Online (Sandbox Code Playgroud)
但我想在函数定义中做到这一点.如果我写
def func(x, a, b, c):
func.latex = r'$ax^2 + bx + c$'
return a*x**2 + b*x + c
Run Code Online (Sandbox Code Playgroud)
这当然有效,但只有在我func第一次调用之后(因为Python在执行函数时是"懒惰的"(?))
我是编写可调用类的唯一选择吗?
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$')
Run Code Online (Sandbox Code Playgroud)
或者是否有一种语言的功能,我忽略了这样做的整洁?
Jim*_*ard 21
实现这一目标的更好方法是使用装饰器,为此您有两个选择:
您可以创建一个基于函数的装饰器,它接受乳胶表示作为参数,并将其附加到它装饰的函数:
def latex_repr(r):
def wrapper(f):
f.latex = r
return f
return wrapper
Run Code Online (Sandbox Code Playgroud)
然后您可以在定义函数时使用它并提供适当的表示:
@latex_repr(r'$ax^2 + bx + c$')
def func(x, a, b, c):
return a*x**2 + b*x + c
Run Code Online (Sandbox Code Playgroud)
这意味着:
func = latex_repr(r'$ax^2 + bx + c$')(func)
Run Code Online (Sandbox Code Playgroud)
并latex在定义函数后立即使该属性可用:
print(func.latex)
'$ax^2 + bx + c$'
Run Code Online (Sandbox Code Playgroud)
我已经使表示成为必需参数,如果您不想强制始终给出表示,您可以定义合理的默认值.
如果类是您的偏好,基于类的装饰器也可以以比您原始尝试更Pythonic的方式用于类似的效果:
class LatexRepr:
def __init__(self, r):
self.latex = r
def __call__(self, f):
f.latex = self.latex
return f
Run Code Online (Sandbox Code Playgroud)
你以同样的方式使用它:
@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$'
Run Code Online (Sandbox Code Playgroud)
这里LatexRepr(r'$ax^2 + bx + c$')初始化类并返回可调用实例(已__call__定义).这样做是:
func = LatexRepr(r'$ax^2 + bx + c$')(func)
# __init__
# __call__
Run Code Online (Sandbox Code Playgroud)
并做同样的事情wrapped.
因为它们都只是为函数添加一个参数,所以它们只是按原样返回.它们不会用另一个可调用的替换它.
虽然基于类的方法可以解决这个问题,但基于函数的装饰器应该更快,更轻巧.
你还问:
"因为Python在执行函数时是"懒惰的":Python只是编译函数体,它不会在其中执行任何语句; 它唯一不执行是默认参数值(见著名的Q 这里).这就是为什么你首先需要调用函数来"获取"属性latex.
这种方法的另一个缺点是每次调用函数时都执行该赋值
由于您将函数视为比普通Python函数更复杂的实体,因此将它们表示为指定的用户定义类的可调用实例(如您所建议的那样)确实很有意义.
但是,一个更简单和常见的方法来做你想要的是使用装饰器:
def with_func_attrs(**attrs):
def with_attrs(f):
for k,v in attrs.items():
setattr(f, k, v)
return f
return with_attrs
@with_func_attrs(latex = r'$ax^2 + bx + c$', foo = 'bar')
def func(...):
return ...
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3326 次 |
| 最近记录: |