Есть какой-нибудь способ изменить словарь местных жителей?

StackOverflow https://stackoverflow.com/questions/1450275

  •  11-09-2019
  •  | 
  •  

Вопрос

locals это встроенная функция, которая возвращает словарь локальных значений.В документации говорится:

Предупреждение

Содержимое этого словаря не должно изменяться;изменения могут не влиять на значения локальных переменных используемых интерпретатором.

К сожалению, exec имеет ту же проблему в Python 3.0.Есть ли какой-нибудь способ обойти это?

Пример использования

Рассмотреть:

@depends("a", "b", "c", "d", "e", "f")
def test():
    put_into_locals(test.dependencies)

dependents хранит строки, указанные в его аргументах, в списке test.dependences.Эти строки являются ключами в словаре d.Я хотел бы иметь возможность писать put_into_locals чтобы мы могли извлечь ценности из d и вложите их в местных жителей.Возможно ли это?

Это было полезно?

Решение

Я только что протестировал exec, и он работает на Python 2.6.2

>>> def test():
...     exec "a = 5"
...     print a
...
>>> test()
5

Если вы используете Python 3.x, это больше не работает, потому что локальные файлы оптимизируются как массив во время выполнения, вместо использования словаря.

Когда Python обнаружит "инструкцию exec", это заставит Python переключить локальное хранилище с массива на словарь.Однако, поскольку "exec" является функцией в Python 3.x, компилятор не может провести это различие, поскольку пользователь мог бы сделать что-то вроде "exec = 123".

http://bugs.python.org/issue4831

Изменять локальные файлы функции на "На лету" невозможно без нескольких последствий:обычно локальные файлы функций хранятся не в словаре, а в массиве, чьи индексы определяются во время компиляции из известных локализаций.Это противоречит по крайней мере, новым локальным файлам, добавленным exec.Старая инструкция exec обходила это, потому что компилятор знал, что если exec без аргументов globals / locals встречается в функции , это пространство имен было бы "неоптимизированным", т.е.не используется массив locals .Поскольку exec() теперь является обычной функцией, компилятор не знает, к чему может быть привязан "exec", и поэтому не может обрабатывать is специально.

Другие советы

Локальные переменные изменяются с помощью операторов присваивания.

Если у вас есть ключи словаря, которые являются строками, пожалуйста, не делайте их также локальными переменными - просто используйте их как ключи словаря.

Если вы абсолютно должен попросите локальные переменные сделать это.

def aFunction( a, b, c, d, e, f ):
    # use a, b, c, d, e and f as local variables

aFunction( **someDictWithKeys_a_b_c_d_e_f )

Это позволит заполнить некоторые локальные переменные из вашего словаря, не делая ничего волшебного.

Это невозможно.Я думаю, это делается для того, чтобы в дальнейшем обеспечить оптимизацию производительности.Байт-код Python ссылается на локальные файлы по индексу, а не по имени;если бы требовалось, чтобы locals() была доступна для записи, это могло бы помешать интерпретаторам реализовать некоторые оптимизации или усложнить их.

Я совершенно уверен, что вы не найдете ни одного базового API, который гарантировал бы, что вы можете редактировать локальные файлы подобным образом, потому что, если бы этот API мог это делать, locals() также не имел бы этого ограничения.

Не забывайте, что все локальные файлы должны существовать во время компиляции;если вы ссылаетесь на имя, которое не привязано к локальному во время компиляции, компилятор предполагает, что оно глобальное.Вы не можете "создать" локальные файлы после компиляции.

Видишь этот вопрос одно из возможных решений, но это серьезный взлом, и вы действительно не хотите этого делать.

Обратите внимание, что в вашем примере кода есть основная проблема:

@depends("a", "b", "c", "d", "e", "f")
def test():
    put_into_locals(test.dependencies)

"test.dependencies" не имеет в виду "f.dependencies", где f - текущая функция;это ссылка на фактическое глобальное значение "test".Это означает, что если вы используете более одного декоратора:

@memoize
@depends("a", "b", "c", "d", "e", "f")
def test():
    put_into_locals(test.dependencies)

это больше не будет работать, поскольку "test" - это обернутая функция memoize, а не depends .Питон действительно нужен способ ссылаться на "выполняемую в данный момент функцию" (и класс).

Я бы сохранил его в переменной:

refs    = locals()
def set_pets():
    global refs
    animals = ('dog', 'cat', 'fish', 'fox', 'monkey')
    for i in range(len(animals)):
        refs['pet_0%s' % i] = animals[i]

set_pets()
refs['pet_05']='bird'
print(pet_00, pet_02, pet_04, pet_01, pet_03, pet_05 )
>> dog fish monkey cat fox bird

И если вы хотите протестировать свой dict, прежде чем помещать его в locals():

def set_pets():
    global refs
    sandbox = {}
    animals = ('dog', 'cat', 'fish', 'fox', 'monkey')
    for i in range(len(animals)):
        sandbox['pet_0%s' % i] = animals[i]
    # Test sandboxed dict here
    refs.update( sandbox )

Python 3.6.1 на macOS Sierra

Я не уверен, подпадает ли он под те же ограничения, но вы можете получить прямую ссылку на текущий фрейм (и оттуда словарь локальных переменных) через модуль inspect:

>>> import inspect
>>> inspect.currentframe().f_locals['foo'] = 'bar'
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'foo', 'inspect']
>>> foo
'bar'
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top