Немного отклонюсь от вопроса и расскажу о том, как устроены области видимости в питоне и что будет, если использовать конструкцию locals = value в разных ситуациях
Всего в питоне есть только три вида областей видимости - модуля (глобальный namespace), класса и функций (локальные).
Все, что определено на уровне модуля (вне классов и функций) - очевидно принадлежит области видимости модуля. Этот namespace является самым верхним в иерархии и для него locals == globals.
>>> globals() is locals()
True
Как следствие - выражение locals = 12 изменит глобальный namespace
Функции и методы.
Поиск переменной работает здесь по такому принципу - если в теле функции есть инициализация переменной, то она считается локальной и поиск ведется только в locals(), если инициализации нет (или явно указано global varname) - в globals(), а затем в __builtin__. Проверка, будет ли инициализирована переменная в теле функции, происходит до выполнения кода функции.
>>> a = 1
>>> def meth():
... print a
... a = 2
...
>>> meth()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in meth
UnboundLocalError: local variable 'a' referenced before assignment
Обойтись без рантайма здесь можно потому, что инициализировать переменную можно только:
#1. Присваиванием
a = 1
#2. Импортированием
import time
#3. Определением нового класса
class A: pass
#4. Определением функции
def fun(): pass
#5. Другими языковыми конструкциями, которые
#(будучи преобразованными в AST) на самом деле
#тоже включают в себя присваивание, точно такое
#же, как и в п. 1:
try:
pass
except Exception, e:
#присваивание переменной e
pass
>>> a = ast.parse("""
... try:
... pass
... except Exception, e:
... pass""")
>>> name_node = a.body[0].handlers[0].name
>>> print name_node, name_node.id
<_ast.Name object at 0x7f35f6f18b10> e
#присваивание здесь есть и можно посмотреть, что имя переменной == 'e'
for i in xrange(10):
#присваивание переменной i
pass
[i for i in xrange(10)]
Во всех этих случаях имя переменной известно зарание, поэтому и нет особых проблем с разбором модуля на области видимости до выполнения кода. Но если вдруг разрешить присваивание locals() = ‘asdf’, то такая проблема возникнет.
Переменные в области видимости класса определяют его тип - когда интерпретатор встречает объявление класса, он создает новую область видимости, выполняет пошагово тело класса, а затем, когда этот namespace готов, связывает его с ClassName.__dict__ (для классов нового типа ClassName.__dict__ - это не настоящий dict, а dictproxy object, но последовательность та же и изменяя locals() также будет менятся соотвествующий атрибут ClassName.attr).
>>> class A:
... global d
... d = locals()
...
>>> d is A.__dict__
True
>>> class A(object):
... locals()['a'] = 1
...
>>> A.a
1
Причем у классов разрешение переменных на локальные и глобальные происходит в рантайме:
>>> a = 1
>>> class A:
... print a
... a = 2
...
1
Я к тому, что выражение locals() = value довольно неочевидная штука, и я бы его не использовал без крайней нужды