判断python对象是否可调用的三种方式及其区别详解


Posted in Python onJanuary 31, 2019

查找资料,基本上判断python对象是否为可调用的函数,有三种方法

使用内置的callable函数

callable(func)

用于检查对象是否可调用,返回True也可能调用失败,但是返回False一定不可调用。

官方文档:https://docs.python.org/3/library/functions.html?highlight=callable#callable

判断对象类型是否是FunctionType

type(func) is FunctionType
# 或者
isinstance(func, FunctionType)

判断对象是否实现 __call__ 方法

hasattr(func, '__call__')

写个小demo,测试下这三种验证方式的区别

from types import FunctionType
__author__ = 'blackmatrix'


class ClassA:

 @staticmethod
 def func_a():
  pass

 @classmethod
 def func_b(cls, arg):
  pass

 def func_c(self, arg):
  pass


def func_d():
 pass

if __name__ == '__main__':

 class_a = ClassA()

 print('静态方法,实例调用验证')
 print("callable(class_a.func_a) result: {result}".format(result=callable(class_a.func_a)))
 print("type(class_a.func_a) is FunctionType result: {result}".format(result=type(class_a.func_a) is FunctionType))
 print("hasattr(class_a.func_a, '__call__') result: {result}".format(result=hasattr(class_a.func_a, '__call__')))

 print('静态方法,类调用验证')
 print("callable(ClassA.func_a) result: {result}".format(result=callable(ClassA.func_a)))
 print("type(ClassA.func_a) is FunctionType result: {result}".format(result=type(ClassA.func_a) is FunctionType))
 print("hasattr(ClassA.func_a, '__call__') result: {result}".format(result=hasattr(ClassA.func_a, '__call__')))

 print('类方法验证')
 print("callable(ClassA.func_b) result: {result}".format(result=callable(ClassA.func_b)))
 print("type(ClassA.func_b) is FunctionType result: {result}".format(result=type(ClassA.func_b) is FunctionType))
 print("hasattr(ClassA.func_b, '__call__') result: {result}".format(result=hasattr(ClassA.func_b, '__call__')))

 print('实例方法验证')
 print("callable(class_a.func_c) result: {result}".format(result=callable(class_a.func_c)))
 print("type(class_a.func_c) is FunctionType result: {result}".format(result=type(class_a.func_c) is FunctionType))
 print("hasattr(class_a.func_c, '__call__') result: {result}".format(result=hasattr(class_a.func_c, '__call__')))

 print('函数验证')
 print("callable(func_d) result: {result}".format(result=callable(func_d)))
 print("type(func_d) is FunctionType result: {result}".format(result=type(func_d) is FunctionType))
 print("hasattr(func_d, '__call__') result: {result}".format(result=hasattr(func_d, '__call__')))

通过运行结果,发现三种方法的验证结果并不相同。

主要是type(func) is FunctionType方法,在验证类方法和实例方法时,会返回False,

从调试的结果上看,实例方法,和类方法的类型都是<class 'method'>,不是FunctionType,所以会返回False

静态方法,实例调用验证
callable(class_a.func_a) result: True
type(class_a.func_a) is FunctionType result: True
hasattr(class_a.func_a, '__call__') result: True
静态方法,类调用验证
callable(ClassA.func_a) result: True
type(ClassA.func_a) is FunctionType result: True
hasattr(ClassA.func_a, '__call__') result: True
类方法验证
callable(ClassA.func_b) result: True
type(ClassA.func_b) is FunctionType result: False
hasattr(ClassA.func_b, '__call__') result: True
实例方法验证
callable(class_a.func_c) result: True
type(class_a.func_c) is FunctionType result: False
hasattr(class_a.func_c, '__call__') result: True
函数验证
callable(func_d) result: True
type(func_d) is FunctionType result: True
hasattr(func_d, '__call__') result: True

因为Python中分为函数(function)和方法(method),函数是Python中一个可调用对象(用户定义的可调用对象,及lambda表达式创建的函数,都是函数,其类型都是FunctionType),方法是一种特殊的类函数。

官方文档中,对于method的定义:

Methods are always bound to an instance of a user-defined class

类方法和类进行绑定,实例方法与实例进行绑定,所以两者的类型都是method。

而静态方法,本身即不和类绑定,也不和实例绑定,不符合上述定义,所以其类型应该是function。

其中还有需要注意的是,如果一个类实现了__call__方法,那么其实例也会成为一个可调用对象,其类型为创建这个实例的类,而不是函数或方法。

class TheClass:

 def __call__(self, *args, **kwargs):
  return self

if __name__ == '__main__':
the_class = TheClass()

# True

print('class_instance callable {callable} '.format(callable=callable(the_class)))

所以通过类型去判断Python对象是否可调用,需要同时判断是函数(FunctionType)还是方法(MethodType),或者类是否实现__call__方法。

如果只是单纯判断python对象是否可调用,用callable()方法会更稳妥。

以上这篇判断python对象是否可调用的三种方式及其区别详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python的Flask框架中实现简单的登录功能的教程
Apr 20 Python
python实现的jpg格式图片修复代码
Apr 21 Python
Python psutil模块简单使用实例
Apr 28 Python
在Python中使用成员运算符的示例
May 13 Python
浅谈Python2.6和Python3.0中八进制数字表示的区别
Apr 28 Python
python中日志logging模块的性能及多进程详解
Jul 18 Python
关于Python中空格字符串处理的技巧总结
Aug 10 Python
Sanic框架请求与响应实例分析
Jul 16 Python
Python面向对象之继承和多态用法分析
Jun 08 Python
Python实现结构体代码实例
Feb 10 Python
Matplotlib 绘制饼图解决文字重叠的方法
Jul 24 Python
Jupyter安装链接aconda实现过程图解
Nov 02 Python
python3使用QQ邮箱发送邮件
May 20 #Python
Python实现FTP弱口令扫描器的方法示例
Jan 31 #Python
对python条件表达式的四种实现方法小结
Jan 30 #Python
python从子线程中获得返回值的方法
Jan 30 #Python
学生信息管理系统Python面向对象版
Jan 30 #Python
python学生管理系统开发
Jan 30 #Python
Python修改文件往指定行插入内容的实例
Jan 30 #Python
You might like
详解Grunt插件之LiveReload实现页面自动刷新(两种方案)
2015/07/31 PHP
php中实现进程锁与多进程的方法
2016/09/18 PHP
Laravel配合jwt使用的方法实例
2020/10/25 PHP
JS正则验证邮箱的格式详细介绍
2013/11/19 Javascript
js限制文本框只能输入整数或者带小数点的数字
2015/04/27 Javascript
微信小程序 css使用技巧总结
2017/01/09 Javascript
js鼠标跟随运动效果
2017/03/11 Javascript
mac下的nodejs环境安装的步骤
2017/05/24 NodeJs
JavaScript字符串_动力节点Java学院整理
2017/06/27 Javascript
js es6系列教程 - 基于new.target属性与es5改造es6的类语法
2017/09/02 Javascript
浅谈react前后端同构渲染
2017/09/20 Javascript
Vue 中使用 CSS Modules优雅方法
2018/04/09 Javascript
微信小程序获取地理位置及经纬度授权代码实例
2019/09/18 Javascript
windows如何把已安装的nodejs高版本降级为低版本(图文教程)
2020/12/14 NodeJs
[02:56]《DAC最前线》之国外战队抵达上海备战亚洲邀请赛
2015/01/28 DOTA
[01:05:52]DOTA2-DPC中国联赛 正赛 Ehome vs Aster BO3 第一场 2月2日
2021/03/11 DOTA
python使用7z解压apk包的方法
2015/04/18 Python
K-近邻算法的python实现代码分享
2017/12/09 Python
python使用turtle库绘制树
2018/06/25 Python
解决python中使用plot画图,图不显示的问题
2018/07/04 Python
python爬虫之urllib,伪装,超时设置,异常处理的方法
2018/12/19 Python
对python判断是否回文数的实例详解
2019/02/08 Python
python 模拟贷款卡号生成规则过程解析
2019/08/30 Python
python 求定积分和不定积分示例
2019/11/20 Python
python如何把字符串类型list转换成list
2020/02/18 Python
TensorFlow-gpu和opencv安装详细教程
2020/06/30 Python
python 浮点数四舍五入需要注意的地方
2020/08/18 Python
美国休闲服装品牌:Express
2016/09/24 全球购物
意大利团购网站:Groupon意大利
2016/10/11 全球购物
国家地理在线商店:Shop National Geographic
2018/06/30 全球购物
领导干部群众路线教育实践活动剖析材料
2014/10/10 职场文书
岗位聘任报告
2015/03/02 职场文书
酒店财务经理岗位职责
2015/04/08 职场文书
重阳节活动主持词
2015/07/04 职场文书
2015秋季田径运动会广播稿
2015/08/19 职场文书
初三化学教学反思
2016/02/22 职场文书