Как я могу принудительно обновить словарь Python locals () для другого кадра стека?

В Python 2 (не уверен насчет 3) словарь locals обновляется только тогда, когда вы действительно вызываете locals (). Так, например,

l=locals()
x=2
l['x']

терпит неудачу, потому что l не содержит ключа "x", но

l=locals()
x=2
locals()
l['x']

возвращает 2.

Я ищу способ принудительно обновить словарь местных жителей, но хитрость в том, что я нахожусь в другом фрейме стека. Так, например, Я хочу сделать

l=locals()
x=2
force_update()
l['x']

и мне нужно написать функцию force_update(). Я знаю, что с помощью указанной функции я могу получить родительский фрейм через inspect.currentframe().f_back и даже родительские (не обновленные) локальные переменные через inspect.currentframe().f_back.f_locals, но как я могу принудительно выполнить обновление?

Если это кажется запутанным, моя главная цель - написать функцию, которая является сокращением для "{some} string".format(**dict(globals(),**locals())), чтобы мне не приходилось каждый раз вводить ее, и вместо этого я могу сделать fmt("{some} string"). При этом я столкнулся с проблемой, описанной выше.

Изменить: с ответом Марджина ниже, по сути, это решение, которое я искал. Можно поиграться с тем, как именно они получают фрейм стека вызываемого объекта, здесь я делаю это через partial.

from functools import partial
from inspect import currentframe

fmt = partial(lambda s,f: s.format(**dict(globals(),**f.f_locals)),f=currentframe())
x=2
print fmt("{x}") #prints "2"

person marius    schedule 17.04.2016    source источник
comment
В своем редакторе вы можете определить ярлык, фрагмент или что-то еще, что редактор называет его расширением до .format(**dict(globals(),**locals())). Многие редакторы поддерживают что-то подобное.   -  person Roland Smith    schedule 17.04.2016
comment
Почему вы так часто используете "{some} string".format(**dict(globals(),**locals())) в своем коде? Действительно ли вашей строке формата нужен доступ ко всем переменным в локальном и глобальном пространствах имен?   -  person Thomas Nelson    schedule 17.04.2016
comment
Если вы можете получить родительский фрейм (см. Также sys._getframe(1)), тогда зачем вам globals() и locals()?   -  person cdarke    schedule 17.04.2016


Ответы (1)


Просто доступ к f_locals в объекте фрейма запускает копирование, поэтому использования inspect.currentframe().f_back.f_locals достаточно.

См. frame_getlocals() функцию в реализации frameobject.c:

static PyObject *
frame_getlocals(PyFrameObject *f, void *closure)
{
    PyFrame_FastToLocals(f);
    Py_INCREF(f->f_locals);
    return f->f_locals;
}

PyFrame_FastToLocals - это функция, используемая для копирования данных из локальных значений отслеживания внутреннего массива в словарь. frame_getlocals используется для реализации дескриптора frame.f_locals (свойства); см. frame_getsetlist определение.

Используемая выше функция PyFrame_FastToLocalsWithError - это именно то, что locals() использует для создания того же словаря (по обертывание _ 12_ функция).

person Martijn Pieters    schedule 17.04.2016
comment
Ага! Спасибо. Мне удалось найти currentframe().f_locals, но я не осознавал, что именно это вызывает обновление, которое я искал. - person marius; 17.04.2016
comment
Да - но будьте осторожны, чтобы не произошло обратного - нет возможности обновить быстрые переменные, изменив значения в локальных. - person jsbueno; 19.04.2016
comment
@CharlieParker: в своем ответе я указал ссылку на исходный код Python 3; да, это работает в Python 3. - person Martijn Pieters; 17.10.2017
comment
@MartijnPieters подожди, а ты действительно можешь обновить местных жителей и все заработает? Я безуспешно искал что-то подобное. Почему твой подход работает, а другие терпят неудачу? - person Charlie Parker; 17.10.2017
comment
@CharlieParker: вы не можете добавлять или обновлять локальные жители через словарь locals() (ни через возвращаемое значение locals(), ни через ссылку f_locals), нет. - person Martijn Pieters; 17.10.2017
comment
@MartijnPieters просто из любопытства, почему это невозможно (даже с вашим решением)? - person Charlie Parker; 17.10.2017
comment
@CharlieParker: см. Измените значение локальной переменной, где имя переменной будет выражено в виде строки, Python сильно оптимизирует пространство имен локальных переменных в функциях. - person Martijn Pieters; 17.10.2017