如果操作员有副作用,会出现什么问题?

时间:2018-06-01 21:02:42

标签: python operator-overloading side-effects

我遇到了一个Python库,它定义了一个类似于以下类的类,其中>>运算符被重载以产生全局副作用:

from collections import defaultdict

class V(object):
    """A Vertex in a graph."""

    graph = defaultdict(list)  # accessed globally

    def __init__(self, label):
        self.label = label

    def __rshift__(self, other):
        V.graph[self].append(other)
        return other

    def __repr__(self):
        return 'V(%r)' % (self.label,)

库是这样做的,因为"它为用户提供了一些很好的语法"用于象征性地构建网络,通过写下简单的表达式,例如:

a = V('a')
b = V('b')
c = V('c')
a >> b >> c >> c

为了构建一个a连接到b的网络,c连接到+,后者经常与自身连接。

*@datetime.timestamp()运营商中也有类似的机制。所有这些行为都记录在案并且是用户期望的。

然而,是否有任何可能发生的奇怪事情,你不会认为表达式应该被评估 - 但实际上是 - 反之亦然?也就是说,Python的执行模型是否假设某些表达式没有任何副作用?我想知道是否有任何先例,或者用户是否需要采取任何特殊预防措施。

2 个答案:

答案 0 :(得分:1)

您已经具体询问了意外评估或非评估。 Python并不认为任何用户定义的运算符都是无副作用的,所以它不会跳过a >> b的错误假设它没有做任何事情。当人们认为某些功能没有做某些事情时,人们偶尔也会遇到问题 - 例如,假设一个迭代的函数不会尝试len - 但是大多数这样的问题同样适用于>>或方法。

您可能会遇到使用其他交互式环境进行假设的问题 - 例如,我可以想象在选项卡完成时遇到问题并尝试评估它不应该做的事情 - 但在实际的Python程序中使用该模块不应该有这样的问题

我在实际程序中对此类问题的最接近的事情将是优先问题。例如,C ++使用<<进行打印会导致类似以下代码的问题:

std::cout << true ? "a" : "b";

which prints 1代替a,因为<<?:更紧密。我可以想象这个库会出现类似的问题。

答案 1 :(得分:0)

我不知道有任何其他Python库可以做到这一点。

对我来说,奇怪或意外的一个例子如下:

a = V('a')
b = V('b')

def do_something(c=a>>b):
    return c>>c

do_something(a)

这可能被认为是一个奇怪的结果(a >> aa >> b),因为无论是否最终使用了默认参数,都会对其进行评估。

另一个例子是,当使用try / except时,任何部分完成的评估都会导致一组不完整的副作用无法重绕。

try:
    a >> b >> c
except NameError:
    # do something else

在这里,错误处理可能需要处理仍然评估a >> b的事实。

我不建议用户执行上述任何一项操作。我只声称如果用户这样做,那么他们可能会遇到令人惊讶,意外或难以调试的行为。