__call__ 方法是python的魔術(shù)方法,就是增加一些特殊功能,我們來看看 __call__ 代表了什么意思?
三門峽網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、成都響應(yīng)式網(wǎng)站建設(shè)公司等網(wǎng)站項目制作,到程序開發(fā),運營維護(hù)。創(chuàng)新互聯(lián)從2013年成立到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。
python中所有的東西都被稱為對象,對象分為可以被調(diào)用和不可以被調(diào)用
可調(diào)用對象:許多Python對象都是我們所說的可調(diào)用的,即是任何通過函數(shù)操作符 () 來調(diào)用的對象
1.例如函數(shù)
函數(shù)是對象,可以被調(diào)用
2.但是如果是類的話會發(fā)生什么情況呢?
Python給類提供了名為 __call__ 的特別方法,該方法允許程序員創(chuàng)建可調(diào)用的對象(實例)。默認(rèn)情況下, __call__ 方法是沒有實現(xiàn)的,這意味著大多數(shù)情況下實例是不可調(diào)用的。
如何解決這一個問題?這里就用到 __call__ 函數(shù)
以上說明 __call__
Iamlaosong文
我們在用for ... in ...語句循環(huán)時,in后面跟隨的對象要求是可迭代對象,即可以直接作用于for循環(huán)的對象統(tǒng)稱為可迭代對象(Iterable),如list、tuple、dict、set、str等。
可迭代對象是實現(xiàn)了__iter__()方法的對象,而迭代器(Iterator)則是實現(xiàn)了__iter__()和__next__()方法的對象,可以顯示地獲取下一個元素。這種可以被next調(diào)用并不斷返回下一個值的對象稱為迭代器。迭代器一定是可迭代對象,反過來則不一定成立。用iter()函數(shù)可以把list、dict、str等Iterable變成Iterator,例如:
bb=[x for x in range(10)]
cc=iter(bb)
cc.next()
循環(huán)變量的值其實可以看著是一次次用next取值的過程,每取一個值,做一次處理。list等對象用于循環(huán)實際上可以看著是用iter()方法產(chǎn)生一個迭代器,然后循環(huán)取值。
生成器(generator)就是一個能返回迭代器的函數(shù),其實就是定義一個迭代算法,可以理解為一個特殊的迭代器。調(diào)用這個函數(shù)就得到一個迭代器,生成器中的yield相當(dāng)于一個斷點,執(zhí)行到此返回一個值后暫停,從而實現(xiàn)next取值。
這兩個方法都能開始線程活動,但是用法不同,其區(qū)別與Java Thread類中start()和run()的區(qū)別類似。
先來看官方文檔的說明:
翻譯過來就是:
start()方法
開始線程活動。
對每一個線程對象來說它只能被調(diào)用一次,它安排對象在一個另外的單獨線程中調(diào)用run()方法(而非當(dāng)前所處線程)。
當(dāng)該方法在同一個線程對象中被調(diào)用超過一次時,會引入RuntimeError(運行時錯誤)。
run()方法
代表了線程活動的方法。
你可以在子類中重寫此方法。標(biāo)準(zhǔn)run()方法調(diào)用了傳遞給對象的構(gòu)造函數(shù)的可調(diào)對象作為目標(biāo)參數(shù),如果有這樣的參數(shù)的話,順序和關(guān)鍵字參數(shù)分別從args和kargs取得。
為了測試寫了如下代碼:
[python]?view plain?copy
#!/usr/bin/python
#?coding=utf-8
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類,我重寫了它的構(gòu)造函數(shù)和run()方法,run()方法通過currentThread()獲取當(dāng)前所處線程名稱并用print函數(shù)打印
然后程序分別執(zhí)行run()和start()方法
輸出結(jié)果如下:
可以看到兩個方法分別處于MainThread和myThread線程中
__call__
在Python中,函數(shù)其實是一個對象:
f = abs
f.__name__
'abs'
f(-123)
由于 f 可以被調(diào)用,所以,f 被稱為可調(diào)用對象。
所有的函數(shù)都是可調(diào)用對象。
一個類實例也可以變成一個可調(diào)用對象,只需要實現(xiàn)一個特殊方法__call__()。
我們把 Person 類變成一個可調(diào)用對象:
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
現(xiàn)在可以對 Person 實例直接調(diào)用:
p = Person('Bob', 'male')
p('Tim')
My name is Bob...
My friend is Tim...
單看 p('Tim') 你無法確定 p 是一個函數(shù)還是一個類實例,所以,在Python中,函數(shù)也是對象,對象和函數(shù)的區(qū)別并不顯著。
任務(wù)
改進(jìn)一下前面定義的斐波那契數(shù)列:
class Fib(object):
???
請加一個__call__方法,讓調(diào)用更簡單:
f = Fib()
print f(10)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
python函數(shù)傳對象對性能有影響。在Python中,一切皆對象,Python參數(shù)傳遞采用的都是“傳對象引用”的方式。實際上,這種方式相當(dāng)于傳值和傳引用的一種綜合。如果函數(shù)收到的是一個可變對象(比如字典或者列表)的引用,就能修改對象的原始值,相當(dāng)于通過“傳引用”來傳遞對象。如果函數(shù)收到的是一個不可變對象(比如數(shù)字、字符或者元組)的引用,就不能直接修改原始對象,相當(dāng)于通過“傳值’來傳遞對象,此時如果想改變這些變量的值,可以將這些變量申明為全局變量。