Определение метода из строки в Python 3 и ссылка на метод
У меня есть необходимость позволить пользователю определить функцию, которая обрабатывает данные в объекте (мудрость и последствия для безопасности в этом были подробно обсуждены в другом вопросе и будут просто дублирующими комментариями здесь.)
Я хотел бы, чтобы функция действовала так же, как любой другой метод. То есть
def my_method(self):...
Будет вызван с:
obj_handle.my_method()
Я почти достиг этого ниже, за исключением того, что функция, результаты которой должны быть явно переданы self
в качестве аргумента, вместо получения его в качестве первого аргумента, как это типично для метода.
Вы можете увидеть это в собственности p
где у меня странный self.process(self)
вызов.
Я представляю, что мне нужно что-то предоставить exec
это как globals()
словарь, но я не уверен в нескольких вещах:
- Это правильно?
- Что эквивалентно
globals()
в классе? - Решает ли это проблему? Если нет, что мне нужно сделать?
Вопрос в том, как мне получить exec()
определенная функция, чтобы действовать как метод объекта?
class test:
def __init__(self, a, b):
self.a=a
self.b=b
@property
def p(self):
return self.process(self)
def set_process(self,program):
func_dict={}
proc_fun = exec(program,func_dict)
setattr(self,'process',func_dict['process'])
def process(self):
return self.a+self.b
t=test(1,2)
prog = '''\
def process(self):
return self.a * self.b
'''
t.set_process(prog)
t.p
2 ответа
Если вы хотите работать с экземплярами, а не с классами:
import types
class Test:
def __init__(self, a, b):
self.a = a
self.b = b
@property
def p(self):
return self.process()
def set_process(self, program):
d = dict()
exec(program, d)
self.process = types.MethodType(d["process"], self)
def process(self):
return self.a + self.b
prog = '''\
def process(self):
return self.a * self.b
'''
t = Test(1, 2)
t.set_process(prog)
print(t.p)
t = Test(1, 2)
print(t.p)
Ответ на комментарий @juanpa.arrivillaga выше:
Установите функцию в классе, если вы хотите, чтобы ее протокол дескриптора работал, и связывали экземпляр с экземпляром при вызове экземпляра. Так что одно решение - просто сделать ваш set_process методом класса. - juanpa.arrivillaga 1 час назад
Рабочий результат
class test:
def __init__(self, a, b):
self.a=a
self.b=b
@property
def p(self):
return self.process()
@classmethod
def set_process(cls,program):
func_dict={}
proc_fun = exec(program,func_dict)
setattr(cls,'process',func_dict['process'])
def process(self):
return self.a+self.b
t=test(1,2)
prog = '''\
def process(self):
return self.a * self.b
'''
test.set_process(prog)
t.p