Поначалу меня это тоже удивило, и, кажется, это странный случай, когда exec не действует ни как определение верхнего уровня, ни как определение внутри вмещающей функции. Похоже, что происходит то, что определение функции выполняется в диктате locals (), который вы передаете. Однако определенная функция фактически не имеет доступа к этому диктанту locals.
Обычно, если вы определяете функцию на верхнем уровне, локальные и глобальные значения совпадают, поэтому функции видны внутри, потому что они могут видеть функцию в глобальных переменных.
Когда функция определена в области видимости другой функции, python заметит, что к ней обращаются внутри функции, и создаст замыкание, чтобы «лошадь» отображала привязку во внешней области видимости.
Здесь это странный случай на полпути. exec действует так, как будто определения находятся на верхнем уровне, поэтому замыкания не создаются. Однако, поскольку локальные значения не совпадают с глобальными, определение не идет туда, где функция может получить к нему доступ - оно определено только в недоступных внешних локальных именах.
Есть пара вещей, которые вы можете сделать:
- Используйте один и тот же словарь для местных и глобальных. то есть "
exec s in locals(),locals()
" (или, что лучше, просто используйте ваш собственный dict). При условии, что только dict globals () имеет тот же эффект - то есть "exec s in mydict
"
#
Поместите функцию в свою собственную функцию, чтобы создать замыкание. например,
s="""
def go():
def factorial(x):
if x==0: return 1
return x*factorial(x-1)
print factorial(10)
go()"""
Заставьте функцию входить в глобальные (), а не в локальные значения, помещая директиву "global funcname", как подсказывает ответ Стефана