以编程方式在Python中创建算术特殊方法(又称工厂函数HOWTO)
我的想法是创建可以求和/减的特定函数对象。。。一起返回具有相同属性的新函数对象。希望此示例代码能够演示以下思想:以编程方式在Python中创建算术特殊方法(又称工厂函数HOWTO),python,class,factory,Python,Class,Factory,我的想法是创建可以求和/减的特定函数对象。。。一起返回具有相同属性的新函数对象。希望此示例代码能够演示以下思想: 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 = qua
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)
我想我错过了一些重要的东西,但我看不到
编辑
迪特里希回答后,我忘了提到一个角落里的案子。假设我想将GenericInput子类化,并且我需要自定义调用方法,而不向构造函数传递可调用的。我必须提供一些示例(实际上这是我最初发布此问题的代码)
在这种情况下,还有一些工作要做。这里有很多不需要存在的代码,而且比需要的更复杂 例如,
\uuuuuu class\uuuuu
属性是所谓的“魔法”属性之一。魔法属性是特殊的,只需要在特殊情况下使用,比如在使用元编程时。这里不需要通过代码创建类
另一个例子是代码中的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,而是使用表达式树。使用表达式树的优点是,可以通过代数操作生成的表达式。例如,你可以求解它们,计算精确的导数,或者把它们打印成方程。我假设你想要
f(x**2)+f(x**3)
返回一个函数x**2+x**3
?你可以试试这个:
class Func:
def __init__(self, func):
self._func = func
def __call__(self, *args):
return self._func(*args)
def __add__(self, other):
def result(*args):
return self._func(*args) + other(*args)
return Func(result)
__radd__ = __add__
def __mul__(self, other):
def result(*args):
return self._func(*args) * other(*args)
return Func(result)
__rmul__ = __mul__
# etc...
这对我很有用,而且比你拥有的要简单得多
编辑:
您甚至可能不必为
self.\u func
调用算术方法而烦恼,只需直接调用self
在您的示例中,plus(1)
是否表示quad(1)+cube(1)
?@inspectorG4dget是,这是预期的行为。
class Func:
def __init__(self, func):
self._func = func
def __call__(self, *args):
return self._func(*args)
def __add__(self, other):
def result(*args):
return self._func(*args) + other(*args)
return Func(result)
__radd__ = __add__
def __mul__(self, other):
def result(*args):
return self._func(*args) * other(*args)
return Func(result)
__rmul__ = __mul__
# etc...