首页 > 解决方案 > 如何/是否可以关闭短路评估?

问题描述

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

这是简化的代码:

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键在更新时永远不会改变,只会改变它们的值。此外,这个问题更像是是否可以控制评估行为

编辑

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

A 正确的输入表达式:

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

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

我无法进一步解释这个在全球范围内的使用,否则我需要一个很长的帖子,丢失似乎不相关的信息来解决这个问题。

标签: python

解决方案


您可以将“验证”代码放入循环中。这是有道理的,因为您的输入正在发生变化,因此您应该在每次更改时对其进行验证。eval每次 dict 值更改时,您已经对表达式进行了评估,因此与当前代码相比,唯一添加的逻辑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

推荐阅读