mar*_*ega 5 python operator-overloading
I'm writing a python program in which I need to overload the >> operator. The problem that I'm facing is that this operator need to be right associative. So if I do the following
A >> B >> C >> D >> E
Run Code Online (Sandbox Code Playgroud)
I want this to be parsed as
(A >> (B >> (C >> (D >> E))))
Run Code Online (Sandbox Code Playgroud)
From what I understand, in python this operator is left associative and so I would get,
((((A >> B) >> C) >> D) >> E)
Run Code Online (Sandbox Code Playgroud)
Is there anyway to change the default associativity of an operator in python when you do operator overloading?
这是可以做到的……但这需要一些努力。基本思想是使用右移运算符来创建和更新推迟实际计算的新型对象。
例如,假设上面的变量:A、B、C、D 和 E 都是 Actual 类型的对象。我们将引入一个新类 Deferred,它是由 Actual 实例上的 rshift 操作生成的。Deferred 还实现了 rshift 运算符,它更新对象并返回自身。
(顺便说一句,对于这个答案的其余部分,我假设 A、B、C、D 和 E 是不可变的,并且 rshift 操作生成一个新对象。)
F = A >> B >> C >> D >> E
Run Code Online (Sandbox Code Playgroud)
计算方式如下...
F = Deferred(A,B) >> C >> D >> E
F = Deferred(A,B,C) >> D >> E
F = Deferred(A,B,C,D) >> E
F = Deferred(A,B,C,D,E)
Run Code Online (Sandbox Code Playgroud)
F 维护 Actual 的缓存实例,该实例是根据相反序列计算得出的。此外,F 实现与 Actual 相同的接口,因此在 Deferred 实例上调用的方法将委托给 Actual 的缓存实例。
我不知道你正在做什么样的计算,所以在下面的例子中,我做了一些微不足道的事情,只是为了证明当延迟计算实际执行时,它们是相反的。
class Var(object):
def __init__(self):
pass
@property
def name(self):
return self._name( )
@property
def length(self):
return len(self.name)
class Actual(Var):
def __init__(self, name):
Var.__init__(self)
self._text = name
def _name(self):
return self._text
def __rshift__(self, other):
if isinstance(other, Actual):
return Deferred(self, other)
return len(self.name)
@staticmethod
def NewFromShiftComputation(sequence):
x = ' >> '.join(reversed(map(lambda actual: actual.name, sequence)))
return Actual(x)
class Deferred(Var):
def __init__(self, *args):
Var.__init__(self)
self._items = [ ]
self._actual = None #-- cached "actual"
for item in args:
self._items.append(item)
def _name(self):
self._assure_actual( )
return self._actual.name
def __rshift__(self, other):
self._actual = None #-- Invalidate the cached "actual"
self._items.append(other)
return self
def _assure_actual(self):
if self._actual is None:
self._actual = Actual.NewFromShiftComputation(self._items)
A = Actual('A')
B = Actual('B')
C = Actual('C')
D = Actual('D')
E = Actual('E')
F = A >> B >> C >> D >> E
print F.name
print F.length
Run Code Online (Sandbox Code Playgroud)