判断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 相关文章推荐
numpy中实现ndarray数组返回符合特定条件的索引方法
Apr 17 Python
Python动态导入模块的方法实例分析
Jun 28 Python
对python文件读写的缓冲行为详解
Feb 13 Python
pandas 使用均值填充缺失值列的小技巧分享
Jul 04 Python
解决pandas展示数据输出时列名不能对齐的问题
Nov 18 Python
推荐8款常用的Python GUI图形界面开发框架
Feb 23 Python
Python实现多线程下载脚本的示例代码
Apr 03 Python
Virtualenv 搭建 Py项目运行环境的教程详解
Jun 22 Python
通过实例解析Python文件操作实现步骤
Sep 21 Python
Python的3种运行方式:命令行窗口、Python解释器、IDLE的实现
Oct 10 Python
python分布式爬虫中消息队列知识点详解
Nov 26 Python
Pytorch如何切换 cpu和gpu的使用详解
Mar 01 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
咖啡常见的种类
2021/03/03 新手入门
php debug 安装技巧
2011/04/30 PHP
Apache实现Web Server负载均衡详解(不考虑Session版)
2013/07/05 PHP
查找php配置文件php.ini所在路径的二种方法
2014/05/26 PHP
yii中widget的用法
2014/12/03 PHP
PHP生成条形图的方法
2014/12/10 PHP
PHP多维数组指定多字段排序的示例代码
2018/05/16 PHP
jquery 模拟雅虎首页的点击对话框效果
2010/04/11 Javascript
动态加载script文件的两种方法
2013/08/15 Javascript
jQuery插件EasyUI校验规则 validatebox验证框
2015/11/29 Javascript
基于js实现的限制文本框只可以输入数字
2016/12/05 Javascript
React如何利用相对于根目录进行引用组件详解
2017/10/09 Javascript
vue文件树组件使用详解
2018/03/29 Javascript
微信小程序实现刷脸登录
2018/05/25 Javascript
vant picker+popup 自定义三级联动案例
2020/11/04 Javascript
[00:47]TI7不朽珍藏III——沙王不朽展示
2017/07/15 DOTA
python获取android设备的GPS信息脚本分享
2015/03/06 Python
在CentOS6上安装Python2.7的解决方法
2018/01/09 Python
Python多层装饰器用法实例分析
2018/02/09 Python
Tensorflow分类器项目自定义数据读入的实现
2019/02/05 Python
浅谈python编译pyc工程--导包问题解决
2019/03/20 Python
分享一个pycharm专业版安装的永久使用方法
2019/09/24 Python
Python调用graphviz绘制结构化图形网络示例
2019/11/22 Python
Python3 实现减少可调用对象的参数个数
2019/12/20 Python
Python3连接Mysql8.0遇到的问题及处理步骤
2020/02/17 Python
Python使用扩展库pywin32实现批量文档打印实例
2020/04/09 Python
解决Keras中Embedding层masking与Concatenate层不可调和的问题
2020/06/18 Python
简单介绍HTML5中的文件导入
2015/05/08 HTML / CSS
党员个人思想汇报
2013/12/28 职场文书
大学生职业规划论文
2014/01/11 职场文书
采购助理岗位职责
2014/02/16 职场文书
学生会宣传部部长竞选演讲稿
2014/04/25 职场文书
离婚协议书标准格式
2014/10/04 职场文书
2015年个人思想总结
2015/03/09 职场文书
严以用权专题学习研讨会发言材料
2015/11/09 职场文书
dubbo集成zipkin获取Traceid的实现
2021/07/26 Java/Android