Ý tưởng của tôi là tạo các đối tượng hàm cụ thể có thể được cộng/trừ/... với nhau, trả về đối tượng hàm mới có cùng thuộc tính. Mã ví dụ này, hy vọng, thể hiện ý tưởng:Lập trình tạo các phương thức đặc biệt số học bằng Python, (aka hàm factory HOWTO)
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)
Tôi đã viết mã sau đây, được hy vọng nhận xét và tài liệu đủ để giải thích những gì tôi muốn đạt được.
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)
Tôi nghĩ rằng tôi thiếu điều gì đó quan trọng nhưng tôi không thể nhìn thấy nó.
EDIT
Sau Dietrich câu trả lời tôi quên đề cập đến một trường hợp góc. Giả sử tôi muốn phân lớp GenericInput và tôi cần phải tùy chỉnh gọi phương thức__, mà không truyền một hàm gọi đến hàm tạo. Tôi phải ví dụ, (thực sự đây là mã mà tôi đã đăng câu hỏi này).
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)
Trong trường hợp này, còn một số việc phải làm.
trong ví dụ của bạn, không 'cộng (1)' có nghĩa là 'quad (1) + khối lập phương (1) '? – inspectorG4dget
@ inspectorG4dget Có, đó là hành vi dự định. – Davide