如何用不同的方法参数名称定义两个相同的类?

2024-05-01 08:00:50 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在开发一个科学图书馆,在那里我将定义时域和频域中的向量函数(通过FFT链接)。我为频域中的向量公式创建了一个类,现在我想为时域定义一个相同的类

我希望在时域中,类函数——尽管与它们的频域孪生函数相同——有一个名为t的参数,而不是omega在保持可读性的同时,是否有更简单的方法来实现这一点,而不是重复定义每个方法?

我的代码:
(注意:我的类要复杂得多,不能只使用函数作为formula.x_func(...)-包括一些检查等。另外,实际上有6个组件。)

class VecFormula(object):
    pass

class FreqFormula(VecFormula):

    def __init__(self, x_func, y_func, z_func):
        self.x_func = x_func
        self.y_func = y_func
        self.z_func = z_func

    def x(self, x, y, z, omega, params):
        return self.x_func(x, y, z, omega, params)

    def y(self, x, y, z, omega, params):
        return self.y_func(x, y, z, omega, params)

    def z(self, x, y, z, omega, params):
        return self.z_func(x, y, z, omega, params)

    def component(self, comp, x, y, z, omega, params):
        if comp == 'x':
            return self.x(x, y, z, omega, params)
        elif comp == 'y':
            return self.y(x, y, z, omega, params)
        elif comp == 'z':
            return self.z(x, y, z, omega, params)
        else:
            raise ValueError(f'invalid component: {comp}')


class TimeFormula(FreqFormula):
    "same as FreqFormula, but the omega parameter is renamed to t"
    
    def x(self, x, y, z, t, params):
        return super(TimeFormula, self).x(x, y, z, t, params)

    def y(self, x, y, z, t, params):
        return super(TimeFormula, self).y(x, y, z, t, params)

    def z(self, x, y, z, t, params):
        return super(TimeFormula, self).z(x, y, z, t, params)

    def component(self, comp, x, y, z, t, params):
        return super(TimeFormula, self).component(x, y, z, t, params)

2条回答

在创建类之后很容易将方法添加到类中,它们只是类属性。这里最困难的部分是,您需要动态创建新函数,从原始类克隆方法,以便能够更改其签名

它不是Python最清晰的部分,官方参考文档中没有记录动态函数创建,但可以在SO上找到:Python: dynamically create function at runtime

所以这里有一个可能的方法:

# have the new class derive from the common base
class TimeFormula(VecFormula):
    "same as FreqFormula, but the omega parameter is renamed to t"
    pass

# loop over methods of origina class
for i,j in inspect.getmembers(FreqFormula, inspect.isfunction):
    # copy the __init__ special method
    if i == '__init__':
        setattr(TimeFormula, i, j)
    elif i.startswith('__'): continue  # ignore all other special attributes
    if not j.__qualname__.endswith('.'.join((FreqFormula.__name__, i))):
        continue   # ignore methods defined in parent classes
    # clone the method from the original class
    spec = inspect.getfullargspec(j)
    newspec = inspect.FullArgSpec(['t' if i == 'omega' else i
                                   for i in spec.args], *spec[1:])
    f = types.FunctionType(j.__code__, j.__globals__, i, newspec, j.__closure__)
    f.__qualname__ = '.'.join((TimeFormula.__qualname__, i))
    # adjust the signature
    sig = inspect.signature(j)
    if ('omega' in sig.parameters):
        f.__signature__ = sig.replace(
            parameters = [p.replace(name='t') if name == 'omega' else p
                          for name, p in sig.parameters.items()])
    # and finally insert the new method in the class
    setattr(TimeFormula, i, f)

听起来您可以通过优雅地使用类继承来实现所需

请查看class inheritance python documentationhere

相关问题 更多 >