Python: вычисление имени функции из другого имени функции
В Python 3.4 я хочу иметь возможность сделать очень простую таблицу диспетчеризации для целей тестирования. Идея состоит в том, чтобы иметь словарь с ключом, представляющим собой строку с именем тестируемой функции, а элемент данных - с именем тестовой функции. Например:
myTestList = (
"myDrawFromTo",
"myDrawLineDir"
)
myTestDict = {
"myDrawFromTo": test_myDrawFromTo,
"myDrawLineDir": test_myDrawLineDir
}
for myTest in myTestList:
result = myTestDict[myTest]()
Идея в том, что у меня есть список имен функций где-то. В этом примере я вручную создаю словарь, который сопоставляет эти имена с именами тестовых функций. Имена тестовых функций являются простым расширением имени функции. Я хотел бы вычислить весь словарь из списка имен функций (здесь это "myTestList").
С другой стороны, если бы я мог сделать то же самое без словаря, это тоже было бы хорошо. Я попытался просто создать новую строку из записей в myTestList и затем использовать local() для установки вызова, но безуспешно. Идея словаря пришла от docs.python.org/3/
2 ответа
Есть две части проблемы.
Легкая часть просто префикс 'text_'
на каждую строку:
tests = {test: 'test_'+test for test in myTestDict}
Сложнее всего на самом деле поиск функций по имени. Подобные вещи обычно плохая идея, но вы столкнулись с одним из случаев (генерация тестов), где это часто имеет смысл. Вы можете сделать это, посмотрев их в глобальном словаре вашего модуля, например так:
tests = {test: globals()['test_'+test] for test in myTestList}
Существуют варианты одной и той же идеи, если тесты живут где-то, кроме глобальной области видимости модуля. Например, было бы неплохо сделать их все методы класса, и в этом случае вы бы сделали:
tester = TestClass()
tests = {test: getattr(tester, 'test_'+test) for test in myTestList}
(Хотя более вероятно, что код будет внутри TestClass
так что будет использовать self
скорее, чем tester
.)
Если вам на самом деле не нужно диктовать, конечно, вы можете изменить понимание на явное for
заявление:
for test in myTestList:
globals()['test_'+test]()
Еще одна вещь: прежде чем изобретать колесо, вы смотрели на тестовые среды, встроенные в stdlib или доступные в PyPI?
Ответ Абарнерта кажется полезным, но он отвечает на ваш первоначальный вопрос о том, как вызвать все тестовые функции для списка имен функций:
def test_f():
print("testing f...")
def test_g():
print("testing g...")
myTestList = ['f', 'g']
for funcname in myTestList:
eval('test_' + funcname + '()')