Выполнить код python и оценить / результаты тестирования

#python

#python

Вопрос:

По общему признанию, я не уверен, как задать этот вопрос, поскольку я знаю, как справиться с этим в R (выполнение кода в новой среде), но эквивалентные поиски решения на python не дают того, на что я надеялся.

Короче говоря, я получу электронную таблицу (или csv), где содержимое столбца, как мы надеемся, будет содержать допустимый код на python. Это может быть эквивалент скрипта, но просто содержащийся в csv / workbook. В качестве примера использования представьте, что вы обучаете программированию, а на выходе получаете LMS.

Что я надеюсь сделать, так это перебрать файл, и для каждой ячейки запустить код, и с результатами в памяти протестировать, существуют ли определенные вещи.

Например: https://docs.google.com/spreadsheets/d/1D-zC10rUTuozfTR5yHfauIGbSNe-PmfrZCkC7UTPH1c/edit?usp=sharing

При оценке первого ответа в приведенной выше таблице я хотел бы проверить, что все x, y и z правильно определены и имеют ожидаемые значения.

Поскольку в файле будет несколько строк, по одной на каждого учащегося, как я могу запустить каждую строку отдельно, оценить результаты и убедиться, что я выделяю результаты только для этой ячейки. Просто, двигаясь дальше, я не сохраняю ни одной из прошлых оценок.

Комментарии:

1. вы ищете exec встроенный , вы можете передать строковый код и словарь для использования в качестве пространства имен переменных, чтобы вы могли проверять его как обычный словарь. Вы спрашиваете о мерах безопасности или этого достаточно?

2. @TadhgMcDonald-Jensen это могло бы сработать, я не знал, поскольку я подхожу к python с точки зрения науки о данных. Позвольте мне взглянуть на пик.

Ответ №1:

(Я не знаю инструментов для проверки кода, поэтому я справляюсь с этим очень ручным способом.)

exec() Функцию Python можно использовать для выполнения строк, таких как содержимое ячеек.

Пример:

 variables = {}
exec("""import os

# a comment
x = 2 
y = 6
z = x * y""", variables)
assert variables["z"] == 12
  

Работа с файлом csv:

 import csv

csv_file = open("path_to_csv_file", "rt")
csv_reader = csv.reader(csv_file)
iterator = iter(csv_reader)
next(iterator) # To skip the titles of the columns

for row in iterator:
    user = row[0]
    answer = row[1]

### Any other code involving the csv file must be put here to work properly,
### that is, before closing csv_file.

csv_file.close() # Remember to close the file.
  

Он не сможет определить, был ли импортирован какой-либо модуль (потому что при импорте из exec() функции модуль останется в кэше для следующего исполнителя). Одним из способов проверить это было бы «отключить» модуль и протестировать exec на наличие исключений.
Пример:

 # This piece of code would be before closing the file,
# INSIDE THE FOR LOOP AND WITH IT IDENTED (Because you want
# it to run for each student.).

try:
    del os # 'unimporting' os (This doesn't 'unimport' as much as deletes a
           # reference to the module, what could be problematic if a 'from
           # module import object' statement was used.)
except NameError: # So that trying to delete a module that wasn't imported
                  # does not lead to Exceptions being raised.
    pass

namespace = dict()
try:
    exec(answer, namespace)
except:
    # Answer code could not be run without raising exceptions, i.e., the code
    # is poorly written.

    # Code you want to run when the answer is wrong.
else:
    # The code hasn't raised Exceptions, time to test the variables.

    x, y, z = namespace['x'], namespace['y'], namespace['z']
    if (x == 2) and (y == 6) and (z == x * y):
        # Code you want to run when the answer is right.
    else:
        # Code you want to run when the answer is wrong.
  

Я чувствую, что это не лучший способ сделать это, но это, безусловно, попытка.
Я надеюсь, что это помогло.

РЕДАКТИРОВАТЬ: удален некоторый неправильный код и добавлена часть комментария Таджа Макдональда-Дженсена.

Комментарии:

1. Спасибо за это. Я, конечно, могу использовать фрагменты этого. Я не знал о exec и возможности сохранять пространство имен как dict для дальнейшей проверки. Я думаю, что между ними у меня есть достаточно для запуска.

2. технически del os это на самом деле не имеет значения для модуля, вам нужно было бы сделать что-то вроде del sys.modules["os"] , но в этот момент вы могли бы также просто создать подпроцесс для запуска каждого из них, чтобы вы могли отслеживать стандартный вывод и каждый раз сбрасывать все модули, но это, вероятно, слишком много для того, что вы хотите, поэтому то, как вы это получили, прекрасно 🙂