Подтвердить что ты не робот

Eval call lambda не видит себя

Вот простой код, иллюстрирующий суть проблемы:

class test:
    def __init__(self):
        self.var = 0
    def set(self, val):
        self.var = val
        print eval('map(lambda x: self.var*x, [1,2,3,4,5])')
f = test()
f.set(10)

В нем говорится

NameError: global name 'self' is not defined

Я знаю, что многим людям не нравится eval, но в моем случае я должен использовать его, потому что он выполняет математическую формулу из строки, введенной пользователем во время выполнения программы. Любые предложения приветствуются! Спасибо заранее!

4b9b3361

Ответ 1

Try:

eval('map(lambda x, self=self: self.var*x, [1,2,3,4,5])')

Нечетный self=self создаст копию self из внешнего контекста во внутренний контекст ( "тело" лямбда-выражения).

Ответ 2

Это сложная ситуация. Прежде всего в качестве обходного пути вы можете использовать:

class test:
    def __init__(self):
        self.var = 0
    def set(self, val):
        self.var = val
        print eval('map(lambda x,self=self: self.var*x, [1,2,3,4,5])')
f = test()
f.set(10)

Причина не просто объяснить... но попробуй.

Когда вы пишете

 lambda x: self.var * x

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

Когда эта лямбда построена с помощью eval, однако эта локальная переменная self не видна внутри eval, и поэтому генерируемая лямбда-функция будет ссылаться на переменную global self, которая не работает В этом случае не существует.

Ответ 3

Eval() также поддерживает установку глобальных и локальных переменных соответственно, чтобы вы могли сделать что-то вроде этого:

class test:
    def __init__(self):
        self.var = 0
    def set(self, val):
        self.var = val
        print eval('map(lambda x: self.var*x, [1,2,3,4,5])', dict(globals().items() + [('self', self)]))
f = test()
f.set(10)

Обновление: В приведенном выше примере теперь хранятся предыдущие глобальные и локальные переменные.

Ответ 4

Хотя я уверен, что есть способ сделать это без eval, попробовали ли вы использовать форматирование строк?

eval('map(lambda x: %s*x, [1,2,3,4,5])'%self.var)

Ответ 5

Более общий ответ: передать локальные переменные в среду eval

Функция eval поддерживает два дополнительных параметра - глобальные и локальные переменные. Так, например, вы можете решить проблему без изменения функции, передав:

eval(map(lambda x: self.var*x + myvar, [1,2,3,4,5]), dict(self=self, myvar=123))