Почему Python3 exec() вызывает AttributeError, когда переменная находится не в локальных, а в gl
Когда я передаю добросовестный диктат для locals
, exec()
делает правильную вещь и возвращается к глобальному словарю для пропущенных имен. Однако, если я передаю LazyMap (объект, похожий на dict) в качестве локальных, доступ к глобальным переменным вызовет AttributeError изнутри лямбда-выражения, данного LazyMap.
#!/usr/bin/env python3
class LazyMap:
def __init__(self, keys, getter):
self._keys = keys
self._getter = getter
def keys(self):
return self._keys
def __getitem__(self, k):
return self._getter(k)
class TestObj:
def __init__(self):
self.field = 'foo'
obj = TestObj()
# this prints 'foo'
locs = dict((name, getattr(obj, name)) for name in dir(obj))
exec('print(field)', globals(), locs)
# this raises AttributeError
locs = LazyMap(dir(obj), lambda k,s=obj: getattr(s, k))
exec('print(field)', globals(), locs)
Почему с LazyMap возникает исключение, а не с простым указанием? Как я могу создать карту местных жителей, которая будет извлекать / вычислять значение только при обращении из exec?
1 ответ
Я думаю, что exec() сначала пытается получить элемент на объекте localals, и если KeyError
поднимается, затем возвращается к объекту globals. Однако в данном коде getattr
вызовет AttributeError вместо KeyError. Изменение пройденной лямбды на vars(s)[k]
приведет к тому, что пропущенный ключ вызовет правильный KeyError.
Подвести итоги: __getitem__
должен поднять KeyError
на недостающий ключ, в то время как __getattr__
должен поднять AttributeError
,