在 Python 2.7.3 中,eval()
函数可以用来执行字符串形式的 Python 表达式,并返回表达式的值。这是一个在进行数学计算时非常有用的功能,尤其是当你需要处理由用户输入的或动态生成的表达式时。然而,使用 eval()
时需要特别小心,因为它也可以执行任意代码,可能导致安全问题。
这里是一个简单的例子,展示如何使用 eval()
来计算数学表达式,并且介绍如何安全地限制 eval()
所执行代码的环境。
1、问题背景
在 Python 2.7.3 中,我需要创建一个函数来进行以下操作:
- 创建一个数学问题并将其作为字符串输出,其中主题是运算顺序。
- 作为输出的第二部分,输出此问题的正确答案。
- 作为其余输出,输出错误答案,但如果更改运算顺序(例如让减法先于乘法),则可以达到这些答案。
该函数不需要任何参数,但在问题过程中需要我们进行以下导入:
import random
from random import choice
这样做是为了生成随机整数作为任何问题的数字,并选择问题中涉及的操作,例如 *,/,+,-。
2、解决方案
有两种解决这个问题的方法:
方法一
- 我通过交替将整数和操作添加到字符串来制作一个字符串(因此以整数结尾),然后在最后在字符串的某些位置加上括号。
- 我使用 eval() 来评估字符串并因此提供正确的答案。
- 我通过在不同的地方插入括号来制作该字符串的其他版本,以便返回不同的答案,然后我使用 eval() 对其进行求值以找到其他答案。
方法二
这类似于方法一,但将元素放入列表中。
- 将运算顺序提供为列表作为输入,例如正确的运算顺序为 [*,(,/),(+,-)],然后找到这些运算在列表中的位置,并对左右的整数执行运算,删除列表的 3 个部分,并用我们找到的答案替换它们。我们对整个列表的所有操作执行此操作,使用重复。
- 我通过输入一个运算顺序方面不同的列表来简单地获得不同的答案,从而使寻找错误答案的步骤变得更容易。
代码例子
方法一
import random
from random import choice
def create_question():
"""Creates a math question as a string."""
# Generate random integers and operations.
integers = [random.randint(1, 10) for _ in range(5)]
operations = choice(['+', '-', '*', '/'])
# Create a string representation of the question.
question = ""
for i in range(len(integers)):
question += str(integers[i])
if i < len(integers) - 1:
question += operations
# Add parentheses to the string in random places.
for _ in range(random.randint(1, 3)):
index = random.randint(0, len(question) - 1)
question = question[:index] + '(' + question[index:]
return question
def evaluate_question(question):
"""Evaluates a math question string and returns the answer."""
return eval(question)
def find_incorrect_answers(question):
"""Finds incorrect answers to a math question string."""
incorrect_answers = []
# Try adding parentheses to the string in different places.
for i in range(len(question)):
if question[i] in ['+', '-', '*', '/']:
new_question = question[:i] + '(' + question[i:] + ')'
incorrect_answers.append(evaluate_question(new_question))
# Try changing the order of operations.
for operation in ['+', '-', '*', '/']:
new_question = question.replace(operation, '')
incorrect_answers.append(evaluate_question(new_question))
return incorrect_answers
# Test the function.
question = create_question()
print("Question:", question)
correct_answer = evaluate_question(question)
print("Correct answer:", correct_answer)
incorrect_answers = find_incorrect_answers(question)
print("Incorrect answers:", incorrect_answers)
方法二
import random
from random import choice
def create_question():
"""Creates a math question as a string."""
# Generate random integers and operations.
integers = [random.randint(1, 10) for _ in range(5)]
operations = choice(['+', '-', '*', '/'])
# Create a list representation of the question.
question = []
for i in range(len(integers)):
question.append(integers[i])
if i < len(integers) - 1:
question.append(operations)
return question
def evaluate_question(question):
"""Evaluates a math question list and returns the answer."""
# Find the indices of the operations.
operation_indices = [i for i, op in enumerate(question) if op in ['+', '-', '*', '/']]
# Evaluate the question using the correct order of operations.
while operation_indices:
# Find the index of the first operation.
index = operation_indices[0]
# Perform the operation.
operation = question[index]
left_operand = question[index - 1]
right_operand = question[index + 1]
result = eval(str(left_operand) + operation + str(right_operand))
# Replace the operation and its operands with the result.
question = question[:index - 1] + [result] + question[index + 2:]
# Update the list of operation indices.
operation_indices = [i - 1 for i in operation_indices if i > index]
# Return the final result.
return question[0]
def find_incorrect_answers(question):
"""Finds incorrect answers to a math question list."""
incorrect_answers = []
# Try changing the order of operations.
for operation in ['+', '-', '*', '/']:
new_question = question.copy()
# Find the indices of the operations.
operation_indices = [i for i, op in enumerate(new_question) if op in ['+', '-', '*', '/']]
# Change the order of operations.
while operation_indices:
# Find the index of the first operation.
index = operation_indices[0]
# Perform the operation.
operation = new_question[index]
left_operand = new_question[index - 1]
right_operand = new_question[index + 1]
result = eval(str(left_operand) + operation + str(right_operand))
# Replace the operation and its operands with the result.
new_question = new_question[:index - 1] + [result] + new_question[index + 2:]
# Update the list of operation indices.
operation_indices = [i - 1 for i in operation_indices if i > index]
# Evaluate the question.
incorrect_answers.append(evaluate_question(new_question))
return incorrect_answers
# Test the function.
question = create_question()
print("Question:", question)
correct_answer = evaluate_question(question)
print("Correct answer:", correct_answer)
incorrect_answers = find_incorrect_answers(question)
print("Incorrect answers:", incorrect_answers)
虽然 eval()
是一个强大的工具,能够动态执行字符串形式的代码,但它的使用需要谨慎,尤其是在处理用户输入的数据时。确保限制 eval()
的执行环境可以帮助防止潜在的安全风险。此外,对于复杂的数学表达式解析和计算,考虑使用像 NumPy
或 SymPy
这样的专门库,这些库提供了更强大、更安全的数学运算支持。