【Python】魔法方法之__call__,将对象当方法使用
1、问题
我刚开始接触爬虫的时候,只是看完了 python 的基础,对 python 的语法还没有一个很深入的了解,在使用 bs4 这个库的时候,对其中某些语法感到非常的惊奇,不明白是怎么实现的。
bs4 的官方文档中说到:find_all()
几乎是 Beautiful Soup 中最常用的搜索方法,所以我们定义了它的简写方法。BeautifulSoup
对象和 tag
对象可以被当作一个方法来使用,这个方法的执行结果与调用这个对象的 find_all()
方法相同,下面两行代码是等价的:
soup.find_all("a")
soup("a")
这里,soup
是一个 BeautifulSoup
对象,soup("a")
这很明显是把对象当方法使用了,这是怎么做到的呢?
2、实现
在 Python 中,除了用户定义的函数,调用运算符(即 ())还可以应用到其他对象上。内置的 callable()
函数用来判断一个对象能否调用。就是说,任何 Python 对象都可以表现得像函数一样,为此,只需实现实例方法 __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)
这背后涉及到的概念叫做可调用对象,Python 数据模型文档列出了 7 种可调用对象。
- 用户定义的函数:使用 def 语句或 lambda 表达式创建。
- 内置函数:使用 C 语言(CPython)实现的函数,如 len 或 time.strftime。
- 内置方法:使用 C 语言实现的方法,如 dict.get。
- 方法:在类的定义体中定义的函数。
- 类:调用类时会运行类的
__new__
方法创建一个实例,然后运行__init__
方法,初始化实例,最后把实例返回给调用方。因为 Python 没有new
运算符,所以调用类相当于调用函数。(通常,调用类会创建那个类的实例,不过覆盖__new__
方法的话,也可能出现其他行为。) - 类的实例:如果类定义了
__call__
方法,那么它的实例可以作为函数调用。 - 生成器函数:使用 yield 关键字的函数或方法。调用生成器函数返回的是生成器对象。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?