self'来自哪里?将成员函数作为threading.Thread的目标
在下面的代码中
class foo:
def __init__(self,x):
self.x = x
def do(self):
print(self.x)
foo1 = foo(1)
foo2 = foo(2)
t1=threading.Thread(target=foo1.do)
t2=threading.Thread(target=foo2.do)
t1.start()
t2.start()
我在用一个已经创建的对象的成员函数作为线程的目标。我在想,为什么这样可以工作?也就是说,线程模块是否做了什么特别的事情来判断可调用引用的另一端是一个成员函数(而不是没有对象上下文的“普通”函数)?我觉得像ftplib.retrlines()这样的常规回调机制只会接受普通的全局函数。这样做是否更好,还是应该完全避免?
slarti
PS:我来自C/C++,这种表现对我来说是新的(不过我很欢迎)。
4 个回答
假设你在C++中写了一个相同的类:
class foo {
int x;
public:
foo(int x_) { x = x_; }
void do() { std::cout << x; }
}
foo f = foo(42);
这里的 &foo::do
是一个指向成员函数的指针,你需要有一个 foo
的实例才能调用它。假设你可以直接传递 f.do
,那么你就不需要其他东西就能在 f
上调用 do()
。这正是Python中“绑定成员”的意思,通过传递 foo1.do
,你实际上是在传递要调用的方法和调用它的实例。
在C++中,这个问题也有解决方案,比如使用一些专有扩展,比如Borland的闭包,或者使用一些库,比如 Boost.Bind。
你可能想了解一下Python的方法对象。
在Python中,self
有点像C++中的this
,不过你需要在方法的声明中写上它。
当你在一个类里面定义一个函数时,它就“变成”了一个方法。当你获取一个对象的方法时,它会变成一个绑定方法,这个方法的第一个参数(self
)会固定为你获取它的那个对象。
试试这个:
class Foo(object):
def do(self):
print x
instance = Foo()
print Foo.do # prints <unbound method Foo.do>
print instance.do # prints <bound method Foo.do of <...>>
# These are equivalent:
Foo.do(instance)
instance.do()
在你的线程案例中并没有发生额外的魔法,这只是普通的Python。
foo1.do
和 foo2.do
是绑定的方法。
我建议你看看以下的文档链接:
- http://docs.python.org/library/stdtypes.html#methods (介绍)
- http://docs.python.org/reference/datamodel.html (深入了解)
以下是第二个链接中的摘录:
当一个绑定的用户定义方法被调用时,底层的函数(im_func)会被调用,并在参数列表前面插入类的实例(im_self)。举个例子,当 C 是一个包含函数 f() 定义的类,而 x 是 C 的一个实例时,调用 x.f(1) 相当于调用 C.f(x, 1)。