如何定义两个相同的 类 方法参数名称不同?
How to define two identical classes with different method parameter names?
我正在开发一个科学图书馆,我将在其中定义时域和频域中的向量函数(由 FFT 链接)。我为频域中的矢量公式创建了一个 class,现在我想为时域定义一个相同的 class。
我希望在时域中,class 函数 - 尽管与它们的频域双胞胎相同 - 有一个名为 t
而不是 omega
的参数。 有没有更简单的方法来实现这一点,而不是重复定义每个方法,同时保持可读性?
我的代码:
(注意:我的 classes 要复杂得多,不能只使用 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)
听起来您可以通过优雅地使用 class 继承来实现您的需要。
在创建后向 class 添加方法很容易,它们只是 class 属性。这里的难点在于,您需要动态创建新函数以从原始 class 克隆方法,以便能够更改它们的签名。
这不是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)
我正在开发一个科学图书馆,我将在其中定义时域和频域中的向量函数(由 FFT 链接)。我为频域中的矢量公式创建了一个 class,现在我想为时域定义一个相同的 class。
我希望在时域中,class 函数 - 尽管与它们的频域双胞胎相同 - 有一个名为 t
而不是 omega
的参数。 有没有更简单的方法来实现这一点,而不是重复定义每个方法,同时保持可读性?
我的代码:
(注意:我的 classes 要复杂得多,不能只使用 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)
听起来您可以通过优雅地使用 class 继承来实现您的需要。
在创建后向 class 添加方法很容易,它们只是 class 属性。这里的难点在于,您需要动态创建新函数以从原始 class 克隆方法,以便能够更改它们的签名。
这不是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)