gpt4 book ai didi

python - 在 Python 中以编程方式创建算术特殊方法(又名工厂函数 HOWTO)

转载 作者:太空狗 更新时间:2023-10-30 01:30:01 27 4
gpt4 key购买 nike

我的想法是创建特定的函数对象,这些函数对象可以一起求和/相减/...,返回一个具有相同属性的新函数对象。希望这个示例代码可以演示这个想法:

from FuncObj import Func

# create some functions
quad = Func(lambda x: x**2)
cube = Func(lambda x: x**3)

# now combine functions as you like
plus = quad + cube
minus = quad - cube
other = quad * quad / cube

# and these can be called
plus(1) + minus(32) * other(5)

我已经编写了以下代码,希望对其进行注释和记录足以解释我想要实现的目标。

import operator

class GenericFunction(object):
""" Base class providing arithmetic special methods.
Use derived class which must implement the
__call__ method.
"""

# this way of defining special methods works well
def __add__(self, operand):
""" This is an example of a special method i want to implement. """
obj = GenericFunction()
# this is a trick from Alex Martelli at
# http://stackoverflow.com/questions/1705928/problem-with-making-object-callable-in-python
# to allow per-instance __call__ methods
obj.__class__ = type(obj.__class__.__name__, (obj.__class__,), {})
obj.__class__.__call__ = lambda s, ti: self(ti) + operand(ti)
return obj

# on the other hand this factory function seems buggy
def _method_factory(operation, name):
""" Method factory.
Parameters
----------
op : callable
an arithmetic operator from the operator module
name : str
the name of the special method that will be created
Returns
-------
method : callable
the __***__ special method
"""
def method(s, operand):
obj = GenericFunction()
obj.__class__ = type(obj.__class__.__name__, (obj.__class__,), {})
obj.__class__.__call__ = lambda s, ti: operation(s(ti), operand(ti))
return obj
return method

__sub__ = _method_factory(operator.__sub__, '__sub__')
__mul__ = _method_factory(operator.__mul__, '__mul__')
__truediv__ = _method_factory(operator.__truediv__, '__div__')


class Func(GenericFunction):
""" A customizable callable object.
Parameters
----------
func : callable
"""
def __init__(self, func):
self.func = func

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


if __name__ == '__main__':

# create some functions
quad = Func(lambda x: x**2)
cube = Func(lambda x: x**3)

# now combine functions
poly_plus = quad + cube
poly_minus = quad - cube

# this is the expected behaviour, and it works well
# since the __add__ method is defined correctly.
assert quad(1) + cube(1) == poly_plus(1)

# this, and the others with * and / result in a "maximum recursion depth exceeded"
assert quad(1) - cube(1) == poly_minus(1)

我想我错过了一些重要的东西,但我看不到它。

编辑

在 Dietrich 回答后,我忘了提及一个极端案例。假设我想子类化 GenericInput 并且我需要自定义 call 方法__,而不将可调用对象传递给构造函数。我必须举个例子,(实际上这是我最初发布这个问题的代码)。

class NoiseInput(GenericInput):
def __init__(self, sigma, a, b, t):
""" A band-pass noisy input. """
self._noise = lfilter(b, a, np.random.normal(0, 1, len(t)))
self._noise *= sigma/self._noise.std()
self._spline = InterpolatedUnivariateSpline(t, self._noise, k=2)

def __call__(self, ti):
""" Compute value of the input at a given time. """
return self._spline(ti)

class SineInput(GenericInput):
def __init__(self, A, fc):
self.A = A
self.fc = fc

def __call__(self, ti):
return self.A*np.sin(2*np.pi*ti*self.fc)

在这种情况下,还有一些工作要做。

最佳答案

这里有很多不需要存在的代码,而且比需要的更复杂。

例如,__class__ 属性是所谓的“神奇”属性之一。魔法属性很特殊,只需要在特殊情况下使用,比如在使用元编程时。此处无需通过代码创建类。

另一个例子是您代码中的 Func 类,它实际上不执行任何操作。您可以安全地将其替换为:

def Func(x):
return x

所以您遇到了相反的问题:您没有“遗漏”任何东西,而是太多了。

class Func(object):
def __init__(self, func):
self._func = func
def __call__(self, x):
return self._func(x)
def __mul__(self, other):
return Func(lambda x: self(x) * other(x))
def __add__(self, other):
return Func(lambda x: self(x) + other(x))
def __sub__(self, other):
return Func(lambda x: self(x) - other(x))

请注意,这不是解决此类问题的传统方法。传统上,人们会避免使用 lambda 并在此处使用表达式树。使用表达式树的优点是可以对生成的表达式进行代数操作。例如,您可以求解它们、计算精确导数或将它们打印为方程式。

关于python - 在 Python 中以编程方式创建算术特殊方法(又名工厂函数 HOWTO),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10842166/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com