Python не может ссылаться на переменную, созданную в exec () из функции [duplicate]

вы должны удалить из iterator (i), а не collection (c) напрямую;

попробуйте это:

for (Iterator<String> i = c.iterator(); i.hasNext();) {
    String s = i.next();
    if(s.equals("lalala")) {
        i.remove(); //note here, changing c to  i with no parameter.
    }
}

EDIT:

Причина, по которой первая попытка вызывает исключение, а вторая - нет, просто из-за количества элементов в вашей коллекции.

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

20
задан Esteban Küber 23 September 2009 в 19:40
поделиться

3 ответа

Эта проблема несколько обсуждается в списке ошибок Python3 . В конечном счете, чтобы получить это поведение, вам нужно сделать:

def foo():
    ldict = {}
    exec("a=3",globals(),ldict)
    a = ldict['a']
    print(a)

И если вы проверите документацию Python3 на exec , вы увидите следующее примечание:

Локали по умолчанию действуют, как описано для функции locals() ниже: не следует пытаться модифицировать словарь локальных файлов по умолчанию. Передайте явный словарь locals, если вам нужно увидеть эффекты кода на локалях после возврата функции exec ().

Обратившись к к определенному сообщению в отчете об ошибке , Георг Брандл говорит:

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

Акцент мой.

Таким образом, суть в том, что Python3 может лучше оптимизировать использование локальных переменных с помощью not , позволяя это поведение по умолчанию.

И ради полноты, как упомянутый в комментариях выше, этот работает , как и ожидалось в Python 2.X:

Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) 
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> def f():
...     a = 1
...     exec "a=3"
...     print a
... 
>>> f()
3
33
ответ дан user2357112 19 August 2018 в 08:46
поделиться
  • 1
    Я вижу, это проблема с locals (), которая была взломана из exec в python 2.X. Эта проблема не так четко документирована, как мне бы хотелось. Exec / locals, изменяющиеся от 2.X до 3.X, следует указать где-нибудь docs.python.org/3.1/library/functions.html#exec , и я думаю, что exec должен иметь параметр удобства, который обходит эта оптимизация ... – ubershmekel 23 September 2009 в 09:51
  • 2
    @MarkRushakoff Я получаю сообщение об ошибке с вашей реализацией в строке exec: TypeError: объект «dict» не может быть вызван – Leo 9 September 2013 в 13:01
  • 3
    @Leo не должно быть ldict, а не dict? Во всяком случае, я больше не работаю на Python, так что если это не так, мы надеемся, что кто-то еще перезвонит. – Mark Rushakoff 12 September 2013 в 07:20

Причина, по которой вы не можете изменять локальные переменные внутри функции, используя exec таким образом, и почему exec действует так, как это делается, можно суммировать следующим образом:

  1. exec - это функция, которая разделяет ее локальную область действия с областью самой внутренней области, в которой она вызвана.
  2. Всякий раз, когда вы определяете новый объект в пределах области действия, он будет доступен в своем локальном пространстве имен, т. е. он изменит словарь local(). Когда вы определяете новый объект в exec, то, что он делает, примерно эквивалентно следующему:

from copy import copy
class exec_type:
    def __init__(self, *args, **kwargs):
        # default initializations
        # ...
        self.temp = copy(locals())

    def __setitem__(self, key, value):
        if var not in locals():
            set_local(key, value)
        self.temp[key] = value

temp - временное пространство имен, которое сбрасывается после каждого экземпляра (каждый время, которое вы вызываете exec).


  1. Python начинает поиск имен из локального пространства имен. Он известен как способ LEGB. Python начинается с Local namespce, затем просматривает области Enclosing, затем Global и в конце просматривает имена в пространстве имен Buit-in.

Более подробный пример будет примерно следующим:

g_var = 5

def test():
    l_var = 10
    print(locals())
    exec("print(locals())")
    exec("g_var = 222")
    exec("l_var = 111")
    exec("print(locals())")

    exec("l_var = 111; print(locals())")

    exec("print(locals())")
    print(locals())
    def inner():
        exec("print(locals())")
        exec("inner_var = 100")
        exec("print(locals())")
        exec("print([i for i in globals() if '__' not in i])")

    print("Inner function: ")
    inner()
    print("-------" * 3)
    return (g_var, l_var)

print(test())
exec("print(g_var)")

Выход:

{'l_var': 10}
{'l_var': 10}

locals являются одинаковыми

{'l_var': 10, 'g_var': 222}

после добавления g_var и изменения l_var он добавляет только g_var и оставил неизменяемый l_var

{'l_var': 111, 'g_var': 222}

l_var, потому что мы меняем и печатаем местные жители в одном экземпляре (один вызов exec)

{'l_var': 10, 'g_var': 222}
{'l_var': 10, 'g_var': 222}

В локальных локалях функции и локальном l_var exec не изменяется, а g_var добавлен

Inner function: 
{}
{'inner_var': 100}
{'inner_var': 100}

inner_function. Локальная такая же, как и локальная команда exec

['g_var', 'test']

global содержит только g_var и имя функции (после исключения специальных методов)

---------------------

(5, 10)
5
1
ответ дан Kasramvd 19 August 2018 в 08:46
поделиться

Если вы находитесь внутри метода, вы можете сделать это:

class Thing():
    def __init__(self):
        exec('self.foo = 2')

x = Thing()
print(x.foo)

Здесь вы можете узнать подробнее

2
ответ дан Macabeus 19 August 2018 в 08:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: