1锨亏、問題
我剛開始接觸爬蟲的時候痴怨,只是看完了 python 的基礎(chǔ),對 python 的語法還沒有一個很深入的了解器予,在使用 bs4 這個庫的時候浪藻,對其中某些語法感到非常的驚奇,不明白是怎么實現(xiàn)的乾翔。
bs4 的官方文檔中說到:find_all()
幾乎是 Beautiful Soup 中最常用的搜索方法爱葵,所以我們定義了它的簡寫方法。BeautifulSoup
對象和 tag
對象可以被當作一個方法來使用,這個方法的執(zhí)行結(jié)果與調(diào)用這個對象的 find_all()
方法相同钧惧,下面兩行代碼是等價的:
soup.find_all("a")
soup("a")
這里暇韧,soup
是一個 BeautifulSoup
對象,soup("a")
這很明顯是把對象當方法使用了浓瞪,這是怎么做到的呢懈玻?
2、實現(xiàn)
在 Python 中乾颁,除了用戶定義的函數(shù)涂乌,調(diào)用運算符(即 ())還可以應(yīng)用到其他對象上。內(nèi)置的 callable()
函數(shù)用來判斷一個對象能否調(diào)用英岭。就是說湾盒,任何 Python 對象都可以表現(xiàn)得像函數(shù)一樣,為此诅妹,只需實現(xiàn)實例方法 __call__
罚勾。
來看一個簡單的示例:
class Sum:
def __init__(self, x, y):
self._x = x
self._y = y
def add(self):
return self._x + self._y
def __call__(self):
return self.add()
sum = Sum(1, 2)
print(sum.add())
print(sum())
print(callable(sum))
輸出:
3
3
True
這樣就明白了,bs4 中亦是如此吭狡,源碼如下:
class Tag(PageElement):
def __call__(self, *args, **kwargs):
return self.find_all(*args, **kwargs)
這背后涉及到的概念叫做可調(diào)用對象尖殃,Python 數(shù)據(jù)模型文檔列出了 7 種可調(diào)用對象。
- 用戶定義的函數(shù):使用 def 語句或 lambda 表達式創(chuàng)建划煮。
- 內(nèi)置函數(shù):使用 C 語言(CPython)實現(xiàn)的函數(shù)送丰,如 len 或 time.strftime。
- 內(nèi)置方法:使用 C 語言實現(xiàn)的方法弛秋,如 dict.get器躏。
- 方法:在類的定義體中定義的函數(shù)。
-
類:調(diào)用類時會運行類的
__new__
方法創(chuàng)建一個實例蟹略,然后運行__init__
方法登失,初始化實例,最后把實例返回給調(diào)用方挖炬。因為 Python 沒有new
運算符揽浙,所以調(diào)用類相當于調(diào)用函數(shù)。(通常茅茂,調(diào)用類會創(chuàng)建那個類的實例捏萍,不過覆蓋__new__
方法的話太抓,也可能出現(xiàn)其他行為空闲。) -
類的實例:如果類定義了
__call__
方法,那么它的實例可以作為函數(shù)調(diào)用走敌。 - 生成器函數(shù):使用 yield 關(guān)鍵字的函數(shù)或方法碴倾。調(diào)用生成器函數(shù)返回的是生成器對象。