Самоанализ Python: определение методов динамического класса во время выполнения

Я пытаюсь создать модульный тест, который проверяет, что каждая функция в mymodule имеет свой собственный экземпляр TestCase.
Чтобы сократить шаблонный код и ручную работу, я хотел использовать самоанализ/рефлексию для динамического добавления lambda функций в качестве методов класса. к изначально пустому классу Test_TestCases.
Следующий вид кода работает — он действительно добавляет лямбда-выражения в качестве методов класса, а unittest.main() находит и правильно их вызывает.

import unittest
from unittest import TestCase

import mymodule

class Test_TestCases(TestCase):
"""Class whose test_* methods will be created during runtime."""
    pass

################################################################################

if __name__ == "__main__":
    for item in dir(mymodule):
        attr = getattr(pws, item)
        if callable(attr):
            testname = "Test_%s" % item
            setattr(Test_TestCases, "test_%s_is_tested" % item,
                    lambda self: self.assertTrue(testname in globals()) and
                    issubclass(getattr(globals(), testname), TestCase))
    unittest.main()

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

lambdas = []
for i in range(5):
    lambdas.append(lambda: str(i))
print ", ".join(f() for f in lambdas)

Я ожидаю этого вывода:

0, 1, 2, 3, 4

но вместо этого я получаю:

4, 4, 4, 4, 4

Кажется, что лямбда-выражения инициализируются лениво.
Может ли кто-нибудь объяснить это поведение или дать мне подсказку о том, как правильно достичь своей цели?

заранее спасибо


person Chris    schedule 26.12.2012    source источник
comment
возможный дубликат Python Lambdas и привязки переменных   -  person interjay    schedule 26.12.2012
comment
возможный дубликат локальных переменных во вложенных функциях Python   -  person Martijn Pieters    schedule 26.12.2012
comment
Это идет в том же направлении и решает мой репродуктор, но моя первоначальная проблема заключается в другом. Предоставление значения по умолчанию не решило бы и не могло решить мою проблему, потому что это не аргумент, передаваемый лямбда-функции, который всегда остается неизменным, а testname, простая переменная, которая не передается в качестве аргумента.   -  person Chris    schedule 26.12.2012


Ответы (1)


Shadow testname с другой функцией-оболочкой:

def assertion(testname=testname):
    def function(self):
        return self.assertTrue(testname in globals()) and issubclass(getattr(globals(), testname), TestCase))

    return function

setattr(Test_TestCases, "test_%s_is_tested" % item, assertion())
person Blender    schedule 26.12.2012