Область действия в eval в понимании списка методом - PullRequest
0 голосов
/ 02 ноября 2018

Меня смущают методы, объединенные со списком и оператором eval. Код ниже ошибки в строке test7 с ошибкой NameError: name 'a2' is not defined.

class test_class(object):
    def __init__(self):
        pass
    @property
    def property(self):
        return 'test_method_run'

def run():
    a2 = test_class()
    test3 = eval('a.property')
    test4 = [eval('a.property') for i in range(10)]
    test5 = eval('a2.property')
    test6 = [a2.property for i in range(10)]
    test7 = [eval('a2.property') for i in range(10)

a = test_class()
test1 = eval('a.property')
test2 = [eval('a.property') for i in range(10)]
run()

Это должно быть как-то связано с областью видимости ( eval терпит неудачу в понимании списка ). Мое понимание области видимости в Python 2 (я только что перешел на Python 3) заключалось в том, что a не должен быть определен в run(), но a2 есть. Я еще больше смущен влиянием понимания списка. Я ожидал, что строки test2 и test3 должны потерпеть неудачу, поскольку a не определено методом test. Также я ожидал, что если test5 работает нормально, тогда test6 и test7 тоже подойдут.

Эта ошибка возникает, только когда eval используется в понимании списка в функции ... Если какой-либо из этих 3 элементов отсутствует, то ошибки нет. Мой вопрос почему? Я не чувствую, что понимаю это достаточно, чтобы сформулировать лучший вопрос.

1 Ответ

0 голосов
/ 02 ноября 2018

Мое понимание области видимости в python 2 (я только что перешел на python 3) заключалось в том, что a не следует определять в run (), а a2 есть.

И a, и a2 видны изнутри run. a определяется в глобальной области видимости, поэтому он виден везде в этом файле.

Я ожидал, что если test5 будет работать нормально, то test6 и test7 также будут в порядке.

В 3.X списочные представления получают свою собственную область. Понимание списка test6 имеет доступ к трем областям: область действия списка, область функции и глобальная область. Таким образом, он имеет доступ к i и a2 и a.

По умолчанию код, выполняемый внутри eval, имеет доступ к двум областям: глобальной области и ближайшей локальной области. Это означает, что test7 eval может обращаться к переменным, определенным на уровне файла, и он может обращаться к переменным, определенным внутри понимания списка, но он не может обращаться к переменным, определенным внутри функции, но вне понимания списка. Он может видеть a и i, но не a2.

В 2.7 списочные представления не имеют собственной области видимости. Они имеют ту же область видимости, что и функция, в которой они определены. Это объясняет, почему ваш код выполняется в 2.7, а не в 3.X. IIRC, это единственное изменение в системе прицела между 2.7 и 3.X. (а если нет, то это единственное изменение, которое имеет отношение к этому сценарию.)

...