eval
может использовать два словаря сопоставления имен и значений для использования в качестве глобального и локального пространств имен, соответственно, для запуска выражения в.
Новый ответ
Проще попросить прощения, чем получить разрешение.
Идея состоит в том, чтобы найти все имена переменных, пытаясь вычислить выражение и поймав NameError
.Обратите внимание, что нам нужно сгенерировать все присвоения переменных для списка переменных, потому что python будет короткое замыкание оценка or
и and
.Например, в var_1 or var_2
мы не найдем var_2
, если var_1
инициализирован в True
.
def variable_names(expression):
# list of found variables
variables = list()
while True:
try:
# generate all assignments for current variable names
assignments = [
{variables[i]: v for i, v in enumerate(vs)}
for vs in itertools.product(
[True, False], repeat=len(variables)
)
]
# try to evaluate them all
for assignment in assignments:
eval(expression, None, assignment)
# all of them work, can return
return variables
except NameError as e:
# get next variable
variables.append(
re.match("name '(.+)' is not defined", str(e)).group(1)
)
Затем мы создадим список словарей назначений - точно так же, как в предыдущем методе- и передайте это eval
, добавив результат в словарь.Затем можно создать DataFrame из записей.
def truth_table(expression):
# get variable names
variables = variable_names(expression)
# make list of assignments
assignments = [
{variables[i]: v for i, v in enumerate(vs)}
for vs in itertools.product([True, False], repeat=len(variables))
]
# get truthy values
values = [
{**assignment, **{"value": eval(expression, None, assignment)}}
for assignment in assignments
]
# make dataframe from records and supply column order
return pd.DataFrame.from_records(values, columns=variables + ["value"])
Старый ответ - фиксированное именование переменных.
Если все ваши переменные имеют имена var_1
, var_2
, ... youможет дать список присваиваний их значению evaluator
и проанализировать их в словарь
def evaluator(expression, values):
return eval(
expression,
None,
{"var_{}".format(i + 1): v for i, v in enumerate(values)},
)
и запустить его следующим образом
evaluator(
"(var_1 and var_2) and (var_3 or not var_4)",
[True, False, True, False]
)
, который возвращает False
.
Полный код для вычисления таблицы истинности из выражения равен
def truth_table(expression):
# get variable names
varnames = set(re.findall(r"(var_\d+)", expression))
# sort by index
varnames = sorted(varnames, key=lambda x: int(x.split("_")[1]))
# get truthy values
values = [
list(x) + [evaluator(expression, x)]
for x in itertools.product([True, False], repeat=len(varnames))
]
return pd.DataFrame(values, columns=varnames + ["T/F"])
Если у вас есть дыр в списке переменных - например, (var_1 and var_3)
- вам понадобитсялибо переименовать их перед вызовом оценщика, либо изменить оценщик на словарь.