Ответ 1
По правилам Python вы не можете изменить свой вызывающий locals
; в текущих реализациях, если вы попробуете (например, с черной магией Анураг предлагает), вы не получите исключение (хотя я бы хотел добавить эту проверку ошибок в какую-то будущую версию), но она будет по сути недействительна, если ваш вызывающий функция (не если ваш вызывающий является модулем верхнего уровня модуля) - фактические локальные переменные вызывающего абонента фактически не будут затронуты. Это означает, что вызывающий locals
явно передан или извлечен черной магией: их все равно нужно рассматривать как только для чтения, если ваш код должен иметь какое-либо здравомыслие.
Скорее, вы могли бы передать вызывающий код в явном, реальном, нормальном dict (который может быть инициализирован из locals()
, если вы хотите), и все изменения, которые ваш код делает в этом dict, все равно будут использоваться для использования вызывающего абонента - просто не как "новые барные имена" в области локального вызова, конечно, но функциональность одинакова, нужно ли вызывающему абоненту использовать x['foo']
или x.foo
или (как вы предпочитаете) просто barename foo
.
BTW, чтобы использовать синтаксис атрибутного доступа, а не синтаксис индексации, вы можете сделать:
class Bunch(object): pass
...
# caller code
b = Bunch()
thefun(b)
print b.foo
...
# called function
def thefun(b):
b.foo = 23
Это также охватывает крошечный вариант, в котором thefun
хочет работать с синтаксисом индексирования dict (например, его тело b['foo'] = 23
вместо b.foo = 23
): в этом случае вызывающему нужно просто используйте thefun(vars(b))
вместо обычного thefun(b)
, но после этого он может продолжать работать с синтаксисом доступа b.foo
.