假设我有一个python类A
:
class A:
def __init__(self, matrix, metadata: list):
self.matrix = np.array(matrix)
self.metadata = metadata
#...
现在,我希望所有算术运算都适合我的班级。他们应该将操作简单地转换为matrix
,即:
def __add__(self, other):
if isinstance(other, type(self)):
raise ValueError("Not allowed.")
else:
return A(
matrix=self.matrix.__add__(other),
metadata=self.metadata,
)
现在的问题是,我必须为每个算术魔术函数重复几乎相同的代码,即__add__, __sub__, __mul__, __truediv__, __pow__, __radd__, __rsub__, __rmul__, __rtruediv__, __iadd__, __isub__, __imul__, __itruediv__, __abs__, __round__, __floor__, __ceil__, __trunc__
。这导致了很多重复的代码。
如何在for循环中动态定义它们?例如
magic_functions = ["__add__", "__sub__", ...]
for magic_function in magic_functions:
# define the method and add it to the class
答案 0 :(得分:0)
operator
模块的目的是解决(广泛)这类问题:
import operator
def mkop(f): # the usual scope for a closure
def op(self,o):
if isinstance(o,type(self)): raise …
return type(self)(matrix=f(self.matrix,o),
metadata=self.metadata)
return op
for op in ['add','sub',…]:
setattr(A,"__%s__"%op,mkop(getattr(operator,op)))
在定义类时,您还可以使用locals()[…]=mkop(…)
(这是其罕见的安全用途之一)进行上述操作。
答案 1 :(得分:0)
在这种情况下,我建议您使用decorator
。可能不是很短,但是您将保存代码的可读性。
import numpy as np
def decorator(fn):
def ret_fn(*args, **kwargs):
if isinstance(args[1], type(args[0])):
raise ValueError("Not allowed.")
else:
return fn(*args, **kwargs)
return ret_fn
class A:
def __init__(self, matrix, metadata: list):
self.matrix = np.array(matrix)
self.metadata = metadata
@decorator
def __add__(self, other):
return A(
matrix=self.matrix.__add__(othe),
metadata=self.metadata,
)
结果:
>>> a1 = A([[1], [2]], [])
>>> a2 = a1 + [[3], [4]]
>>> print(a2.matrix)
[[4]
[6]]
>>> a1 + a1
Traceback (most recent call last):
...
raise ValueError("Not allowed.")
ValueError: Not allowed.
我不知道您的函数之间有多少区别,但是您可以重写装饰器,并且该函数非常简单:
装饰器
def decorator(fn):
def ret_fn(*args, **kwargs):
if isinstance(args[1], type(args[0])):
raise ValueError("Not allowed.")
else:
return A(
matrix=fn(*args, **kwargs),
metadata=args[0].metadata,
)
return ret_fn
方法
@decorator
def __add__(self, other):
return self.matrix.__add__(other)