Использование setattr для замораживания некоторых параметров метода

Чтобы автоматически генерировать параметризованные тесты, я пытаюсь добавить методы в класс, заморозив некоторые параметры существующего метода. Вот кусок кода Python 3

class A:
    def f(self, n):
        print(n)

params = range(10)

for i in params:
    name = 'f{0}'.format(i)
    method = lambda self: A.f(self, i)
    setattr(A, name, method)

Тем не менее, следующие строки дают довольно разочаровывающий результат

a = A()
a.f0()

печатает "9" (вместо "0"). Должно быть, я что-то делаю не так, но не вижу, что. Вы можете помочь?

большое спасибо


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

2 ответа

Решение

Пытаться

method = lambda self, i=i: A.f(self, i)

потому что иначе, когда вы вызываете метод iвозможно, значение изменилось

Лучший способ "заморозить" параметры в Python - это использовать functools.partial, Это примерно эквивалентно лямбда-версии warwaruk, но если у вас есть функция с большим количеством аргументов, вы хотите заморозить только один или два из них (или если вы знаете только определенные аргументы и не заботитесь об остальных), используя partial более элегантно, поскольку вы указываете только те аргументы, которые хотите заморозить, вместо того, чтобы повторять всю сигнатуру функции в лямбда-выражении.

Пример для вашей программы:

class A:
    def f(self, n):
        print(n)

from functools import partial

for i in range(10): # params
    setattr(A, 'f{0}'.format(i), partial(A.f, n=i))

В зависимости от того, какую версию Python 3 вы используете, вам может не потребоваться включать 0 в формате строки заполнителя; начиная с 3.1, iirc, он должен быть автоматически заменен.

Другие вопросы по тегам