【问题标题】:How to / is that possible to turn off short-circuit evaluation?如何/是否可以关闭短路评估?
【发布时间】:2021-10-10 14:13:01
【问题描述】:

我正在编写一种命令行用户界面,可以将任意布尔表达式作为输入。必须在某个更新后更改的字典上重复评估此表达式。

这是简化的代码:

import traceback


def update_my_dict():
    return {'a': 1}


my_dict = {'a': 0}

bool_exp = input()

# -- verify code can be executed in the current context
try:
    result = eval(bool_exp, my_dict)
except Exception:
    print(f'Expression cannot be evaluated, evaluation raise the following error:')
    print(traceback.format_exc())
    quit()

# -- verify code return a boolean
if not isinstance(result, bool):
    print(f'Expression return {type(result)}, expect bool')
    quit()

# -- go
while not eval(bool_exp, my_dict):
    my_dict = update_my_dict()

在运行最后一个 while 循环之前,我想验证表达式是否可以在当前上下文中执行,并确保它返回一个布尔值。

我的问题是,如果表达式是,例如 bool_exp = a == 1 and b == 2 表达式的第一个测试评估,同时返回 false 但不引发异常,因为关闭了惰性评估。但是当my_dict 更新时,就会报错。

那么,是否可以通过某种方式禁用第一次测试评估的惰性/短路评估?我使用ast 搜索了一些解决方案,但它似乎很复杂,因为bool_exp 可以是任意长且复杂的,例如包含纠缠的布尔表达式等。

PS:我知道eval() 在一般情况下是不安全的,但我的代码将无法在外部使用

PS2:我知道它可以在 while 循环中捕获异常,但它看起来有点优化,因为知道 my_dict 键在更新时永远不会改变,只会改变它们的值。此外,这个问题更像是是否可以控制评估行为

编辑

“但你可以使用 &| 代替 andor !” 不,我不知道将输入什么作为输入。所以用户可以输入任何他想要的。

正确的输入表达式:

  1. 应该返回一个布尔值。
  2. 在测试中应该只涉及字典键。

“正确”意味着它将在结束的 while 循环中重复评估,而不会引发任何异常。 我们假设字典中的键将保持不变。即只有字典的值会在更新阶段发生变化。换句话说,第一个try/except 旨在验证表达式仅对my_dict 中的变量进行一些测试。

我无法进一步解释它的全球使用情况,否则我需要很长的帖子,丢失看似无关的信息来解决问题。

【问题讨论】:

  • 这能回答你的问题吗? Python: Avoid short circuit evaluation
  • 请问您真正想用这段代码实现什么?
  • @Welgriv 但问题是布尔运算符对吗?正如链接问题的答案所建议的那样,您可以轻松地 replace 与非短路对应物 &|
  • @L.Grozinger 二元运算符&| 与逻辑运算符andor 的优先级不同。最重要的是,它们位于比较运算符==<、...的对立面。
  • 不,不会。您已经在每次更新时对其进行评估:while not eval(bool_exp, my_dict):。唯一添加的操作是if not isinstance(result, bool):,我高度怀疑会以任何方式影响性能

标签: python


【解决方案1】:

您可以将“验证”代码放入循环中。这是有道理的,因为您的输入正在发生变化,因此您应该在每次更改时对其进行验证。每次 dict 值更改时,您已经 evaluate 表达式,因此与当前代码相比,唯一添加的逻辑是 isinstance 检查现在与 dict 的每次更改一样:

import traceback

def update_my_dict():
    return {'a': 1}

my_dict = {'a': 0}

bool_exp = input()

# -- go
while True:
    # -- verify code can be executed in the current context
    try:
        result = eval(bool_exp, my_dict)
    except Exception:
        print(f'Expression cannot be evaluated, evaluation raise the following error:')
        print(traceback.format_exc())
        quit()

    # -- verify code return a boolean
    if not isinstance(result, bool):
        print(f'Expression return {type(result)}, expect bool')
        quit()

    if result:
        break

    my_dict = update_my_dict()

在相同的示例输入 a == 1 and b == 2 这将输出:

Expression cannot be evaluated, evaluation raise the following error:
Traceback (most recent call last):
  File "main.py", line 14, in <module>
    result = eval(bool_exp, my_dict)
  File "<string>", line 1, in <module>
NameError: name 'b' is not defined

【讨论】:

    猜你喜欢
    • 2016-11-26
    • 2016-02-19
    • 2021-09-23
    • 1970-01-01
    • 2013-10-18
    相关资源
    最近更新 更多