Python运算符重载和运算符关联性

Python运算符重载和运算符关联性,python,operator-overloading,Python,Operator Overloading,我正在编写一个python程序,其中需要重载>>操作符。我面临的问题是,这个操作符必须是右关联的。因此,如果我做以下几点 A >> B >> C >> D >> E 我想把它解析为 (A >> (B >> (C >> (D >> E)))) 据我所知,在python中,这个操作符是左联想的,所以我会得到 ((((A >> B) >> C) >> D) >&

我正在编写一个python程序,其中需要重载>>操作符。我面临的问题是,这个操作符必须是右关联的。因此,如果我做以下几点

A >> B >> C >> D >> E
我想把它解析为

(A >> (B >> (C >> (D >> E))))
据我所知,在python中,这个操作符是左联想的,所以我会得到

((((A >> B) >> C) >> D) >> E)

在执行运算符重载时,python中是否仍有更改运算符默认关联性的方法?

这不是运算符的问题。Python从左到右求值:


因此,在这种情况下需要括号,因为它都是相同的运算符

这是可以做到的……但这需要一些努力。其基本思想是使用right shift操作符创建和更新一种新类型的对象,以延迟实际计算

例如,假设上面的变量:A、B、C、D和E都是类型为Actual的对象。我们将引入一个新的延迟类,该类是由对实际实例的rshift操作生成的。Deferred还实现rshift操作符,它更新对象并返回自身

(顺便说一句,对于这个答案的其余部分,我假设A、B、C、D和E是不可变的,并且rshift操作生成一个新对象。)

将被计算为

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)
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

我可能错了,但这不是运算符重载的问题,而是标准的“操作顺序”问题吗?如果它们都是同一个操作符,那么它将从左到右重载@wim,我想到了,哈哈。只是习惯于从左到右阅读的人用另一种方式阅读要自然得多。我还考虑过重载=操作符,因为我认为这是正确的关联,但那会非常难看。这个用例是什么?重载标准操作符来完成神奇的事情几乎总是一个坏主意,因为这会让其他人(或者你在六个月内)很难理解和维护代码。考虑<代码> DEF FUNC(*ARGs):…和<代码> FUNC(A,B,C,D,E)。虽然你可能还是通过一个吻,一个名字很好的功能更好。Python并不适合在Python本身中创建自定义DSL,因为语法很难扩展。我相信你们可以玩,但它很乱,我很害怕。我只是希望有一种方法可以让python解释器在某些情况下改变运算符的关联性。@martega:是的,如果可以更改interp的规则,这可能会破坏您正在使用的其他lib。为什么不创建一个函数,将它们作为参数,并按照正确的操作顺序运行呢?
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