2013-02-24 2 views
0

Codeacademy에 기본 생물 정보학 코스를 작성하려고합니다. 그들은 코스 작성을위한 좋은 인터페이스를 가지고 있지만, 저장해야하고 미리보기를 한 다음 실행해야하기 때문에 테스트하기에는 약간 느립니다.exec에 의해로드 된 임의의 변수를 가져 와서 함수에서 사용하는 방법

그래서 나는 그 중 하나를 모방 한 약간의 테스트 환경을 작성하려고합니다. 작동하는 것처럼 보이는 것은 사용자 입력 코드가 문자열로 함수에 읽혀지며 코드의 str 인스턴스가 모두 unicode (정규식을 사용했습니다)으로 변환 된 다음 코드가 exec으로 실행됩니다. .

Submission Test을 통합하고 싶을 때 까다로운 부분이있는 것 같습니다.

제출 테스트는 True, False 또는 str을 반환해야하며 함수 본문으로 작성됩니다. 그래서 예를 들면 :

내가 뭘 찾고있어의 단순화 된 버전 :

# 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을 보일 수 없다 이 경우).

제출 테스트에서 코드를 실행할 수는 있지만 가능하면 피하고 싶습니다. 그렇지 않으면 각 테스트에 코드를 추가해야합니다.이 코드는별로 만족스럽지 않습니다!

는 어떤 도움을 크게 감상 할 수있다 :)

+0

코드가 깨졌습니다. 예를 들어 submission은'code_check = None'과 같은 것을 포함 할 수 있습니다.'submission_test = code_check (code, CC, error)'줄에서'TypeError : 'NoneType'객체가 호출 가능하지 않습니다. 그건 그렇고 :'== True'와'== False'를 사용하는 것은 객체의 진리 값을 검사하는 잘못된 방법입니다. 그냥'submission_test : print ("passed") ...'를 사용하거나'is' 연산자를 사용하십시오. – Bakuriu

+0

헤드 업 바큐 리 감사합니다. 이것은 단지 내부 테스트를위한 것입니다. 실제 구현은 Codeacademy입니다.나는 그들의 주자 기능이 어떻게 작동하는지 모르겠습니다. 나는 그들의 기능을 모방하려고 노력하고 있지만, 러너 기능의 보안에 대해 너무 걱정할 필요가 없습니다. 나는'is' 사용법으로 편집 할 것입니다. –

+0

제출 된 코드와 제출 된 테스트를 하나의 문자열로 연결하고 그것에'exec'을 실행할 수 있습니까? – unutbu

답변

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) 
2

exec mystr in somedict 경우, somedict 파이썬 코드로 mystr의 실행 중에 할당 된 모든 변수에 대한 참조를 가지고있다. 또한이 방법으로 변수를 전달할 수도 있습니다.

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

사용자 코드를 실행하여 가져온 사전을 전달해야합니다. 그러면 제출 체크 코드가 적절한 값을 확인할 수 있습니다.

+0

흠, 사전을 사용하는 대신 제출 테스트에서 변수로 호출 할 수있는 것을 선호합니다. 이것은 주로 CodeCademy 시스템을 모방 한 시스템을 가지며 변경없이 두 코드간에 코드를 복사하고 붙여 넣을 수있게합니다. –

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) 
+0

이것은 좋은 소식입니다! 불행하게도, 학생들의 실수에 상관없이 제출 테스트가 필요하므로 유용한 질문에 대한 피드백을 돌려 줄 수 있습니다. 현재로서는 일반적인 오류 처리가 필요합니다. 그게 도움이된다면, 제 질문 코드를 단순화했습니다 :) –

관련 문제