Есть ли способ повлиять на местных жителей во время выполнения? - PullRequest
0 голосов
/ 08 октября 2009

Я действительно хочу создать новый локальный. Я знаю, это звучит сомнительно, но я думаю, у меня есть хороший пример для этого. По сути, моя проблема в том, что этот код выдает «NameError: глобальное имя« eggs »не определено», когда я пытаюсь напечатать яйца:

def f():
    import inspect
    frame_who_called = inspect.stack()[1][0]
    frame_who_called.f_locals['eggs'] = 123

def g():
    f()
    print(eggs)

g()

Я нашел эту старую вещь: http://mail.python.org/pipermail/python-dev/2005-January/051018.html

Что означало бы, что я мог бы сделать это, используя ctypes и вызывая некоторую секретную функцию, хотя они говорили только об обновлении значения. Но может быть, есть более простой способ?

Ответы [ 3 ]

3 голосов
/ 08 октября 2009

Мне очень любопытно, что касается вашего варианта использования. Почему, черт возьми, вы пытаетесь вставить новую локализацию в кадр звонящего, а не просто делать что-то вроде этого:

def f():
    return 123

def g():
    eggs = f()
    print(eggs)

В конце концов, вы можете вернуть кортеж с любым количеством значений:

def f():
    return 123, 456, 789

def g():
    eggs, ham, bacon = f()
    print(eggs, ham, bacon)
2 голосов
/ 08 октября 2009

Как упомянул Грег Хьюгилл в комментарии к вопросу, я ответил на другой вопрос об изменении locals в Python 3, и здесь я приведу немного резюме.

В списке ошибок Python 3 есть сообщение об этой проблеме - оно несколько плохо документировано в руководствах по Python 3. Python 3 использует массив для локальных компьютеров вместо словаря, как в Python 2 - преимущество заключается в более быстром поиске локальных переменных (Lua делает это тоже). По сути, массив определяется как "время компиляции bytecode" и не может быть изменен во время выполнения.

См., В частности, последний абзац в Пост Георга Брандля о списке ошибок , чтобы получить более подробную информацию о том, почему это не может (и, вероятно, никогда не будет) работать в Python 3.

1 голос
/ 08 октября 2009

В Python 2. * вы можете заставить работать такой код, победив обычную оптимизацию локальных систем:

>>> def g():
...   exec 'pass'
...   f()
...   print(eggs)

Наличие оператора exec приводит к тому, что Python 2 компилирует g совершенно неоптимизированным образом, поэтому локальные данные находятся в dict, а не в массиве, как обычно. (Производительность может быть значительной).

Эта «де-оптимизация» не существует в Python 3, где exec больше не является оператором (даже не ключевым словом, а просто функцией) - даже если поставить скобки после него, это не поможет ... :

>>> def x():
...   exec('a=23')
...   print(a)
... 
>>> x()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in x
NameError: global name 'a' is not defined
>>> 

То есть, даже exec теперь не может "создавать локальные объекты", которые не были известны в def (то есть, когда компилятор сделал свой проход, чтобы превратить тело функции в байт-код).

Лучше всего было бы сдаться. Во-вторых, лучше всего было бы, чтобы ваша f функция вставляла новые имена в globals - вызывающего, в конце концов, эти все еще являются диктатом.

...