#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"]
, но в этот момент вы могли бы также просто создать подпроцесс для запуска каждого из них, чтобы вы могли отслеживать стандартный вывод и каждый раз сбрасывать все модули, но это, вероятно, слишком много для того, что вы хотите, поэтому то, как вы это получили, прекрасно 🙂