MetaPython:向类添加方法

时间:2020-12-01 18:15:02

I would like to add some methods to a class definition at runtime. However, when running the following code, I get some surprising (to me) results.

我想在运行时向类定义添加一些方法。但是,在运行以下代码时,我得到一些令人惊讶的(对我而言)结果。

test.py

class klass(object):
    pass

for i in [1,2]:
    def f(self):
        print(i)
    setattr(klass, 'f' + str(i), f)

I get the following when testing on the command line:

在命令行上进行测试时,我得到以下信息:

>>> import test
>>> k = test.klass()
>>> k.f1()
2
>>> k.f2()
2

Why does k.f1() return 2 instead of 1? It seems rather counter intuitive to me.

为什么k.f1()返回2而不是1?这似乎与我相反。

notes

This test was done using python3.0 on a kubuntu machine.

该测试是在kubuntu机器上使用python3.0完成的。

2 个解决方案

#1


It's the usual problem of binding -- you want early binding for the use of i inside the function and Python is doing late binding for it. You can force the earlier binding this way:

这是绑定的常见问题 - 你想要在函数内部使用i进行早期绑定,而Python正在为它进行后期绑定。您可以通过这种方式强制执行早期绑定:

class klass(object):
    pass

for i in [1,2]:
    def f(self, i=i):
        print(i)
    setattr(klass, 'f' + str(i), f)

or by wrapping f into an outer function layer taking i as an argument:

或者通过将f作为参数将f包装到外部函数层中:

class klass(object):
    pass

def fmaker(i):
    def f(self):
        print(i)
    return f

for i in [1,2]:
    setattr(klass, 'f' + str(i), fmaker(i))

#2


My guess is that it's because print (i) prints i not by value, but by reference. Thus, when leaving the for loop, i has the value 2, which will be printed both times.

我的猜测是因为print(i)打印的不是价值,而是参考。因此,当离开for循环时,我有值2,它将被打印两次。

#1


It's the usual problem of binding -- you want early binding for the use of i inside the function and Python is doing late binding for it. You can force the earlier binding this way:

这是绑定的常见问题 - 你想要在函数内部使用i进行早期绑定,而Python正在为它进行后期绑定。您可以通过这种方式强制执行早期绑定:

class klass(object):
    pass

for i in [1,2]:
    def f(self, i=i):
        print(i)
    setattr(klass, 'f' + str(i), f)

or by wrapping f into an outer function layer taking i as an argument:

或者通过将f作为参数将f包装到外部函数层中:

class klass(object):
    pass

def fmaker(i):
    def f(self):
        print(i)
    return f

for i in [1,2]:
    setattr(klass, 'f' + str(i), fmaker(i))

#2


My guess is that it's because print (i) prints i not by value, but by reference. Thus, when leaving the for loop, i has the value 2, which will be printed both times.

我的猜测是因为print(i)打印的不是价值,而是参考。因此,当离开for循环时,我有值2,它将被打印两次。