前言
在关于
Python
描述符函数的详解三篇中,我们有提到如何基于类创建一个“描述符函数”,之所以能够基于类创建这样一个概念,是因为用到了类中的
__call__
属性,从前述文章中可知,当类中定义了
__call__
属性时,基于该类所创建的对象就成为一个可被调用的函数。这样的做法我们已经知道,可是这中间的运行机制是怎样的呢?这一篇文章中,我们将从函数的可被调用性入手来深入分析一下。
Python中的可调用操作符
当我们谈到在
Python
中调用一个函数时,通常指的是在特定函数名后紧跟一对小括号,当然如果有参数的话,将参数包括在小括号中,甚至有人将函数名后的成对小括号称为“调用操作符”,如果函数名后不带成对小括号,那么
Python
解释器只是给出这是一个函数的提示,并不会运行它,比如先定义一个函数
say_hello
:
def say_hello(): print("Hello Python!")
当不带对成小括号时:
say_hello输出:<function __main__.say_hello()>
从上述输出可知,
Python
解释器只是告诉我们
say_hello
是一个函数,如果带上成对小括号,那么该函数就会被执行:
say_hello()输出:Hello Python!
很显然,所有的函数都是可被调用的。
但是当任意给出一个对象时,我们如何知道它是否可以被调用呢?
难道要对每一个给定的对象都带上成对小括号进行测试吗?
如果真是这样的话,我们来看看那些不能被调用的对象带上成对小括号后,结果会怎样,比如我们来定义一个字符串,看看字符串是否可被调用:
hello = "Hello, Python!"hello()
上述代码在执行时
被解释器报出错误,从提示来看,是说
str
对象不具备可调用性,那么,有没有一种方便的方法来测试哪些对象可被调用,哪些又不可被调用呢?
答案是肯定,那就是
callable()
函数。
callable()
函数
在
Python
的内置函数中,有一个
callable()
函数恰好是专门用来测试一个对象是否可被调用,当该对象可被调用时,它返回
True
,否则返回
False
,比如我们用它来测试一下上面创建的函数
say_hello()
函数和
hello
字符串:
>>> callable(say_hello)>>> 输出:True>>> callable(hello)>>> 输出:False
在之前的文章中,我们知道
lambda
函数是匿名函数,那么这类函数是可被调用的吗?下面一个例子可给出说明:
>>> callable(lambda x: x*x)>>> 输出:True
从输出结果可知,
lambda
函数同样属于可被调用的对象。
类是可被调用的吗?
从上面的分析,我们知道函数是可被调用的,字符串是不可被调用的,那么类是可被调用的吗?为了方便起见,我们不用创建特别的类,就用
Python
的内置几个类即可,比如
str
、
int
、
dict
、
list
,这些都是
Python
中最基本的类,更重要的是,它们都可以被紧跟其后的成对小括号来创建一个对象,比如我们常用的
dict()
等,因此,我们可猜测:它们都是可被调用的。下面来验证一下该结论:
types = [str, int, dict, list]for item in types: print("{} | callable: {}".format(type(item), callable(item)))
从上述输出结果可知,这些基本类都是可被调用的,那么,我们自定义的类是否为可调用的呢?下面我们创建一个自定义类来看一下:
class person: pass>>> callable(person)>>> 输出:True
上述结果表明,我们自定义的类也是可被调用的,也就是说
person()
这样的调用是被准许的。但由上述创建的类
person
实例化的一个对象是否还可被调用呢?我们来继续测试:
p1 = person()p1()
程序出错了,从错误提示来看,是说由
person
类创建的对象不具备可调用性。我们用
callable()
测试一下:
>>> callable(p1)>>> 输出:False
果然,
person
类的实例不能被调用,那么我们是否可以创建出一个可被调用的类实例呢?
答案依然是肯定的。
可被调用的类实例
在
Python
中,有一个特别的方法叫做
__call__
,它可以帮我们实现刚才的想法,比如我们重新修改
person
类:
class person: def __init__(self, name): self.name = name def __call__(self): return "你好,{}!".format(self.name)
在上述类中,我们用
__init__
方法完成对类实例的初始化,它接受一个名字做为新实例了名字,同时该类中也实现了
__call__
方法,它使得创建的实例具备了可调用性:
>>> p2 = person("花花")>>> p2()>>> 输出:'你好,花花!'
非常棒!只要在所创建的类中实现
__call__
方法,则所创建的类实例便拥有了可调用的特性,也正是这样,才使得基于类创建“描述符函数”成为可能。
小结
在这篇文章中,我们分析了对象的可调用性,并介绍了用来测试对象是否可被调用的
callable()
函数,之后又研究了如何在普通的类中添加
__call__
方法来创建一个可被调用的类实例,这些内容属于
Python
知识点的较深度分析,供大家参阅。