在以下代码中
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 ++,暴露的行为对我来说是新的(尽管欢迎)。
答案 0 :(得分:4)
您可能想了解Python的method objects。
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。
答案 1 :(得分:2)
foo1.do
和foo2.do
是绑定方法。
我建议您查看以下文档链接:
摘自第二个链接:
当调用绑定的用户定义方法对象时,底层 函数(im_func)被调用,插入类实例(im_self) 在参数列表前面。例如,当C是一个类时 包含函数f()的定义,x是C的实例, 调用x.f(1)等同于调用C.f(x,1)。
答案 2 :(得分:1)
假设您在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
:那么你就不需要在do()
上呼叫f
了。这正是绑定成员在Python中的作用,并通过传递foo1.do
您传递的方法和要调用它的实例onm。
C ++也解决了同样的问题,无论是使用专有扩展,例如Borland的闭包,还是使用库,例如Boost.Bind。
答案 3 :(得分:0)
在类中的任何实例(非静态)方法中,该方法应该在其运行的类的实例中使用一些变量吗?因此,每个实例方法都需要复制运行它的对象来访问这些变量。这就是self
是运行该方法的对象的副本。
在大多数语言中,它隐式地是实例方法中的一个参数(所以你不需要在方法中写出self
,而是在每个实例方法中都有, but in python its explicitly shown, so you have a parameter called
self`。它不会改变任何东西,它只是一种更明显的方式来显示发生的事情。