如何获取exec加载的任意变量,并在函数中使用它们

时间:2013-02-24 13:03:44

标签: python python-2.7 exec

我希望在Codeacademy上写一篇基本的生物信息学课程。他们有一个很好的编写课程的界面,但测试有点慢,因为必须保存,然后预览,然后运行。

所以我想写一个模仿他们的测试环境。看起来如何工作是用户输入代码作为字符串读入函数,代码中的所有str实例都转换为unicode(我刚刚使用了正则表达式)然后用exec执行代码。

当我想要合并Submission Test时,似乎很棘手。

提交测试需要返回TrueFalsestr,并作为函数体写入。例如:

我正在寻找的简化版本:

# The submission test must be a function.
def test_code(code, CC, error):
    # Use information from errors in student code
    if error:
        return "Yada yada %s" %error

    # Use information in the raw student code
    if len(code.split("\n")) is not 2:
        return "This should be accomplished in 2 lines"

    # Have direct access to variables from the student code
    # I'd like to avoid params['y'] if possible.
    try:
        y
    except NameError:
        return "Please use the variable y"

    if y is not 8:
        return "Wrong! Check stuff"

    # Use information from print output
    if str(y) not in CC:
        return "Remember to print your variable!"

    return True

# Read in student code
student_code = """y = 8
                  print y
                  potato"""

# Catch print output
CC = StringIO.StringIO()
sys.stdout = CC

# Execute student code and catch errors
try:
    exec student_code
except Exception as e:
    error = e

# Start outputting to the terminal again
sys.stdout = sys.__stdout__

# Run the submission test
submission_test = test_code(student_code, CC.split("\n"), error)

# Output the result of the submission test
if submission_test is True:
    print("Well done!")
elif submission_test is False:
    print("Oops! You failed... Try again!")
else:
    print(submission_test)

但是,我似乎无法将exec code中的变量传递给提交测试函数(在这种情况下为test_code)。

我可以在提交测试中执行代码,但是如果可能的话我想避免使用它,否则它将被添加到每个测试中,这似乎是单声道的!

非常感谢任何帮助:)

3 个答案:

答案 0 :(得分:2)

如果您exec mystr in somedict,那么somedict会引用在执行mystr期间指定的每个变量作为Python代码。此外,您也可以通过这种方式传递变量。

>>> d = {'y': 3}
>>> exec "x = y" in d
>>> d['x']
3

您需要传递运行用户代码的字典,以便提交检查代码可以验证其中的值是否合适。

答案 1 :(得分:1)

听起来您希望codetest在同一环境中运行。两者都是作为字符串提交的,所以最简单的方法是连接两者并在组合字符串上运行exec

from __future__ import unicode_literals

def wrap_body(body):
    indent = ' '*4
    return 'def test():\n' + indent + body.replace('\n','\n'+indent)    

code = '''
bool_1 = True
bool_2 = False

str_1 = 'Hello there!'
str_2 = "I hope you've noticed the apostrophe ;)"
'''

code_test = '''
try:
    bool_1, bool_2, str_1, str_2
except NameError:
    return "Please do not alter the variable names!"

if (bool_1 == bool_2 or str_1 == str_2):
    return "Please ensure that all of your variables are different " \
           "from one another"

if type(bool_1) != bool: return "bool_1 is incorrect"
if type(bool_2) != bool: return "bool_2 is incorrect"
if type(str_1) != unicode: return "str_1 is incorrect"
if type(str_2) != unicode: return "str_2 is incorrect"

return True
'''
code_test = wrap_body(code_test)
template = code + code_test
namespace = {}
try:
    exec template in namespace
    print(namespace['test']())
except Exception as err:
    print(err)

答案 2 :(得分:0)

好的,我的同事想出了这个。

它使用Devin Jeanpierre的答案元素。

我们使用exec code in dictionary方法,然后将字典传递给检查函数,然后在检查函数中将字典解压缩到globals()

# The submission test must be a function.
def test_code(code, CC, error, code_vars):

    # unpack the student code namespace into the globals()
    globs = globals()
    for var, val in code_vars.items():
        globs[var] = val

    # Use information from errors in student code
    if error:
        return "Yada yada %s" %error

    # Use information in the raw student code
    if len(code.split("\n")) is not 2:
        return "This should be accomplished in 2 lines"

    # Have direct access to variables from the student code
    # I'd like to avoid params['y'] if possible.
    try:
        y
    except NameError:
        return "Please use the variable y"

    if y is not 8:
        return "Wrong! Check stuff"

    # Use information from print output
    if str(y) not in CC:
        return "Remember to print your variable!"

    return True

# Read in student code
student_code = """y = 8
                  print y
                  potato"""

# Catch print output
CC = StringIO.StringIO()
sys.stdout = CC

# create the namespace for the student code
code_vars = {}

# Execute student code and catch errors
try:
    # execute the student code in the created namespace
    exec student_code in code_vars
except Exception as e:
    error = e

# Start outputting to the terminal again
sys.stdout = sys.__stdout__

# Run the submission test
submission_test = test_code(student_code, CC.split("\n"), error, code_vars)

# Output the result of the submission test
if submission_test is True:
    print("Well done!")
elif submission_test is False:
    print("Oops! You failed... Try again!")
else:
    print(submission_test)