Динамическое добавление методов в класс Python

У меня есть словарь классов:

classes = { 'cls1' : Class1, 'cls2' : Class2 }

Здесь Class1, Class2 — это классы Python, которые я определил, и каждый из них имеет методы foo() и bar().

Допустим, у меня есть еще один класс под названием OtherClass. Я хочу повторить приведенный выше словарь и динамически добавить некоторые методы в OtherClass следующим образом:

for k,v in classes.items():
  setattr(OtherClass, 'foo_' + k, lambda x: v().foo())
  setattr(OtherClass, 'bar_' + k, lambda x: v().bar())

Это добавляет методы foo_cls1, bar_cls1, foo_cls2 и bar_cls2 в OtherClass, как и ожидалось. Но похоже, что вызовы foo_cls1 и bar_cls1 перенаправляются на foo_cls2 и bar_cls2 соответственно. То есть определения методов, добавленные позже, «перезаписывают» ранее добавленные (при условии, что порядок итерации словаря — cls1, за которым следует cls2). Для дальнейшего уточнения проблемы, если я сделаю следующее после вышеуказанного цикла:

other = OtherClass()
other.foo_cls2() # Calls Class2.foo() -- Correct
other.foo_cls1() # Also calls Class2.foo() -- Unexpected behavior

other.bar_cls2() # Calls Class2.bar() -- Correct
other.bar_cls1() # Also calls Class2.bar() -- Unexpected behavior

Любая идея, что происходит, и как это исправить?


person Hiranya Jayathilaka    schedule 04.08.2015    source источник
comment
Это связано с использованием вами лямбда и тем, как происходит эта привязка: см., например, stackoverflow.com/questions/7368522/   -  person Two-Bit Alchemist    schedule 04.08.2015
comment
Кроме того, почему вы таким образом исправляете классы обезьян? Почти наверняка есть лучший способ сделать то, что вы пытаетесь сделать.   -  person Two-Bit Alchemist    schedule 04.08.2015
comment
Лямбда с аргументом по умолчанию работает. Спасибо за быстрые ответы. Что касается альтернативных подходов, то я пытаюсь расширить функциональность OtherClass на основе записей в словаре классов. Это требует добавления новых методов в OtherClass (просто так устроен класс, и я не могу его контролировать). Мысли?   -  person Hiranya Jayathilaka    schedule 04.08.2015
comment
Или не используйте лямбду: setattr(OtherClass, 'foo_' + k, v().foo)   -  person Richard_wth    schedule 18.08.2019