Функция динамической функции создания функции python def

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

У меня есть файл mymod.py который я буду импортировать в качестве модуля:

def exec_test0(): print "i am exec_test0"
def exec_test1(): print "i am exec_test1"

и файл test.py с определением класса, который должен прочитать модуль:

import mymod as mm
class MyClass(): def __init__(self): self.l = [fn for fn in dir(mm) if fn.startswith('exec_')] self.create_method() def create_method(self): # i expect this to create new methods with unique properties # as attributes of an object of this class for fn_exec in self.l: # this is the function template # that i want to call the relevant function from the # module mymod (mm) def method(self): method_to_call = getattr(mm, fn_exec) method_to_call() # this should create a new name based on the fn_exec # and assign method to it name_def = fn_exec.replace('exec_', 'do_') setattr(self.__class__, name_def, method)
if __name__ == '__main__': my_obj = MyClass() my_obj.do_test0() my_obj.do_test1()

Результатом запуска test.py является:

i am exec_test1
i am exec_test1

Я жду:

i am exec_test0
i am exec_test1

Любая помощь в том, как добиться этого, очень ценится!

Обновление: ответ приведен ниже, но я собираюсь написать краткую модификацию здесь и расширение для новых функций в классе, чтобы принимать входные данные.

Метод create_method() в test.py должен быть обновлен, как указано в принятом ответе ниже:

def create_method(self): # i expect this to create new methods with unique properties # as attributes of an object of this class for fn_exec in self.l: # this is the function template # that i want to call the relevant function from the # module mymod (mm) # because this run at runtime, it requires a param instead def method(self, fn=fn_exec): method_to_call = getattr(mm, fn) method_to_call() # this should create a new name based on the fn_exec # and assign method to it name_def = fn_exec.replace('exec_', 'do_') setattr(self.__class__, name_def, method)

Кроме того, если нужно передать параметры новому методу, например, create_method() some_input, create_method() будет обновляться следующим образом:

def create_method(self): # i expect this to create new methods with unique properties # as attributes of an object of this class for fn_exec in self.l: # this is the function template # that i want to call the relevant function from the # module mymod (mm) # because this run at runtime, it requires a param instead def method(self, some_input, fn=fn_exec): method_to_call = getattr(mm, fn) method_to_call() print(some_input) # this should create a new name based on the fn_exec # and assign method to it name_def = fn_exec.replace('exec_', 'do_') setattr(self.__class__, name_def, method)

и главный блок может выглядеть так:

if __name__ == '__main__': my_obj = MyClass() my_obj.do_test0('a') my_obj.do_test1('b')

который будет иметь следующий результат:

i am exec_test0
a
i am exec_test1
b
2 ответа

Имя fn_exec в теле method не оценивается до fn_exec method, после чего fn_exec имеет последнее значение, которое потребовалось for цикла for. Чтобы убедиться, что его значение в method времени определено, используется, вам нужно использовать значение параметра по умолчанию:

def method(self, fn=fn_exec): method_to_call = getattr(mm, fn) method_to_call()

Когда method определен, fn устанавливается равным текущему значению fn_exec, поэтому это значение используется при определении method_to_call.


Это связано с тем, как замыкания работают на Python. Добавьте метод, например:

def make_wrapper(self, method_to_call): def method(self): method_to_call()

И измените create_method() на:

def create_method(self): for fn_exec in self.l: method_to_call = getattr(mm, fn_exec) method = self.make_wrapper(method_to_call) name_def = fn_exec.replace('exec_', 'do_') setattr(self.__class__, name_def, method)

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

setattr(self, name_def, method.__get__(self, self.__class__))
# Instead of
setattr(self.__class__, name_def, method)

licensed under cc by-sa 3.0 with attribution.