在我的课程中,我经常使用this site中的重载来定义他们在使用+
,-
等运算符时的行为,方法是覆盖__add__
,{ {1}}等方法。
一个例子是:
__sub__
在链接这些被覆盖的运算符时,有没有办法定义行为?
例如,通过同时考虑所有三个元素而不仅仅是按顺序计算class MyClass:
def __add__(self, other):
result = my_custom_adder(self, other)
return self.__class__(result)
,可以更有效地实现复杂类的三个元素a + b + c
的添加。
原因我可以介绍一种类方法:
(a + b) + c
然后,我可以拨打class MyClass:
def __add__(self, other):
return self.my_custom_adder(self, other)
@classmethod
def my_custom_adder(cls, *args):
result = do_efficient_addition(*args)
return cls(result)
。但这要求用户知道有这样的方法并明确地调用它,而不是仅仅使用my_custom_adder(a, b, c)
。
答案 0 :(得分:1)
不,这种钩子方法确实没有任何东西可以知道它们是更大的等式的一部分。
你可以做的是产生一个中间结果对象,一个收集对象的东西,只有当你需要结果进行实际计算时才会这样做。
例如,如果您的对象类似于整数,并实现__int__
method以促进转换,则中间值可以推迟计算直到那时:
class BaseIntValue(object):
def __init__(self, value):
self.value = value
def __repr__(self):
attrs = ', '.join([f"{k}={v!r}" for k, v in vars(self).items()])
return f'{type(self).__name__}({attrs})'
def __int__(self):
return int(self.value)
def __add__(self, other):
if not isinstance(other, BaseIntValue):
return NotImplemented
return IntermediarySummedIntValue(self, other)
class IntermediarySummedIntValue(BaseIntValue):
def __init__(self, *values):
self.values = values
def __int__(self):
print("Expensive calculation taking place")
return sum(map(int, self.values))
def __add__(self, other):
if not isinstance(other, BaseIntValue):
return NotImplemented
if isinstance(other, IntermediarySummedIntValue):
values = self.values + other.values
else:
values = self.values + (other,)
return IntermediarySummedIntValue(*values)
演示:
>>> BaseIntValue(42) + BaseIntValue(81) + BaseIntValue(314)
IntermediarySummedIntValue(values=(BaseIntValue(value=42), BaseIntValue(value=81), BaseIntValue(value=314)))
>>> int(BaseIntValue(42) + BaseIntValue(81) + BaseIntValue(314))
Expensive calculation taking place
437
答案 1 :(得分:0)
+
,-
等等是二进制运算符。
>>> tree=ast.parse('a+b+c')
>>> astpretty.pprint(tree)
Module(
body=[
Expr(
lineno=1,
col_offset=0,
value=BinOp(
lineno=1,
col_offset=3,
left=BinOp(
lineno=1,
col_offset=0,
left=Name(lineno=1, col_offset=0, id='a', ctx=Load()),
op=Add(),
right=Name(lineno=1, col_offset=2, id='b', ctx=Load()),
),
op=Add(),
right=Name(lineno=1, col_offset=4, id='c', ctx=Load()),
),
),
],
)
所以,不,没有办法覆盖那些操作符来获得你想要的东西。
使用静态方法。