__call__ 方法是python的魔术方法,就是增加一些特殊功能,我们来看看 __call__ 代表了什么意思?
python中所有的东西都被称为对象,对象分为可以被调用和不可以被调用
可调用对象:许多Python对象都是我们所说的可调用的,即是任何通过函数操作符 () 来调用的对象
①例如函数
函数是对象,可以被调用
Python给类提供了名为 __call__ 的特别方法,该方法允许程序员创建可调用的对象(实例).默认情况下, __call__ 方法是没有实现的,这意味着大多数情况下实例是不可调用的.
如何解决这一个问题?这里就用到 __call__ 函数
以上说明 __call__
Iamlaosong文
我们在用for ... in ...语句循环时,in后面跟随的对象要求是可迭代对象,即可以直接作用于for循环的对象统称为可迭代对象(Iterable),如list、tuple、dict、set、str等.
可迭代对象是实现了__iter__()方法的对象,而迭代器(Iterator)则是实现了__iter__()和__next__()方法的对象,可以显示地获取下一个元素.这种可以被next调用并不断返回下一个值的对象称为迭代器.迭代器一定是可迭代对象,反过来则不一定成立.用iter()函数可以把list、dict、str等Iterable变成Iterator,例如:
bb=[x for x in range(10)]
cc=iter(bb)
cc.next()
循环变量的值其实可以看着是一次次用next取值的过程,每取一个值,做一次处理.list等对象用于循环实际上可以看着是用iter()方法产生一个迭代器,然后循环取值.
生成器(generator)就是一个能返回迭代器的函数,其实就是定义一个迭代算法,可以理解为一个特殊的迭代器.调用这个函数就得到一个迭代器,生成器中的yield相当于一个断点,执行到此返回一个值后暂停,从而实现next取值.
这两个方法都能开始线程活动,但是用法不同,其区别与Java Thread类中start()和run()的区别类似.
先来看官方文档的说明:
翻译过来就是:
start()方法
开始线程活动.
对每一个线程对象来说它只能被调用一次,它安排对象在一个另外的单独线程中调用run()方法(而非当前所处线程).
当该方法在同一个线程对象中被调用超过一次时,会引入RuntimeError(运行时错误).
run()方法
代表了线程活动的方法.
你可以在子类中重写此方法.标准run()方法调用了传递给对象的构造函数的可调对象作为目标参数,如果有这样的参数的话,顺序和关键字参数分别从args和kargs取得.
为了测试写了如下代码:
[python]?view plain?copy
#!/usr/bin/python
import?threading
class?myThread(threading.Thread):
def?__init__(self,?threadID,?name,?counter):
threading.Thread.__init__(self)
self.threadID?=?threadID
self.name?=?name
self.counter?=?counter
def?run(self):
currentTreadname?=?threading.currentThread()
print?"running?in",?currentTreadname
thread?=?myThread(1,"mythrd",1)
thread.run()
thread.start()
myThread继承自Thread类,我重写了它的构造函数和run()方法,run()方法通过currentThread()获取当前所处线程名称并用print函数打印
然后程序分别执行run()和start()方法
输出结果如下:
可以看到两个方法分别处于MainThread和myThread线程中
__call__
在Python中,函数其实是一个对象:
f = abs
f.__name__
'abs'
由于 f 可以被调用,所以,f 被称为可调用对象.
所有的函数都是可调用对象.
一个类实例也可以变成一个可调用对象,只需要实现一个特殊方法__call__().
我们把 Person 类变成一个可调用对象:
class Person(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
def __call__(self, friend):
print 'My name is %s...' % self.name
print 'My friend is %s...' % friend
现在可以对 Person 实例直接调用:
p = Person('Bob', 'male')
p('Tim')
My name is Bob...
My friend is Tim...
单看 p('Tim') 你无法确定 p 是一个函数还是一个类实例,所以,在Python中,函数也是对象,对象和函数的区别并不显著.
任务
改进一下前面定义的斐波那契数列:
class Fib(object):
请加一个__call__方法,让调用更简单:
f = Fib()
print f(10)
python函数传对象对性能有影响.在Python中,一切皆对象,Python参数传递采用的都是"传对象引用"的方式.实际上,这种方式相当于传值和传引用的一种综合.如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值,相当于通过"传引用"来传递对象.如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象,相当于通过"传值'来传递对象,此时如果想改变这些变量的值,可以将这些变量申明为全局变量.