我遇到了一个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的执行模型是否假设某些表达式没有任何副作用?我想知道是否有任何先例,或者用户是否需要采取任何特殊预防措施。
答案 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 >> a
和a >> b
),因为无论是否最终使用了默认参数,都会对其进行评估。
另一个例子是,当使用try
/ except
时,任何部分完成的评估都会导致一组不完整的副作用无法重绕。
try:
a >> b >> c
except NameError:
# do something else
在这里,错误处理可能需要处理仍然评估a >> b
的事实。
我不建议用户执行上述任何一项操作。我只声称如果用户这样做,那么他们可能会遇到令人惊讶,意外或难以调试的行为。