判断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的urllib模块显示下载进度示例
Jan 17 Python
Python中用Descriptor实现类级属性(Property)详解
Sep 18 Python
Python的Flask框架中@app.route的用法教程
Mar 31 Python
python在linux系统下获取系统内存使用情况的方法
May 11 Python
Python 模块EasyGui详细介绍
Feb 19 Python
今天 平安夜 Python 送你一顶圣诞帽 @微信官方
Dec 25 Python
Python简单过滤字母和数字的方法小结
Jan 09 Python
Python使用Beautiful Soup爬取豆瓣音乐排行榜过程解析
Aug 15 Python
详细分析Python垃圾回收机制
Jul 01 Python
Python Process创建进程的2种方法详解
Jan 25 Python
M1芯片安装python3.9.1的实现
Feb 02 Python
解决hive中导入text文件遇到的坑
Apr 07 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
PHP使用fopen与file_get_contents读取文件实例分享
2016/03/04 PHP
PHP实现绘制二叉树图形显示功能详解【包括二叉搜索树、平衡树及红黑树】
2017/11/16 PHP
TP5框架安全机制实例分析
2020/04/05 PHP
js 剪切板应用clipboardData详细解析
2013/12/17 Javascript
基于jQuery通过jQuery.form.js插件使用ajax提交form表单
2015/08/17 Javascript
vue.js中$watch的用法示例
2016/10/04 Javascript
详解javascript表单的Ajax提交插件的使用
2016/12/29 Javascript
网页中的图片查看器viewjs使用方法
2017/07/11 Javascript
JS+HTML5实现图片在线预览功能
2017/07/22 Javascript
详解Vue的computed(计算属性)使用实例之TodoList
2017/08/07 Javascript
JavaScript实现HTML5游戏断线自动重连的方法
2017/09/18 Javascript
基于vue-cli 打包时抽离项目相关配置文件详解
2018/03/07 Javascript
vue打包相关细节整理(小结)
2018/09/28 Javascript
基于jquery ajax的多文件上传进度条过程解析
2019/09/11 jQuery
Vue.js组件使用props传递数据的方法
2019/10/19 Javascript
微信小程序wx.navigateTo方法里的events参数使用详情及场景
2020/01/07 Javascript
如何基于filter实现网站整体变灰功能
2020/04/17 Javascript
微信小程序入门之指南针
2020/10/22 Javascript
Python验证企业工商注册码
2015/10/25 Python
解决Python字典写入文件出行首行有空格的问题
2017/09/27 Python
TensorFlow模型保存和提取的方法
2018/03/08 Python
PyQt5每天必学之事件与信号
2018/04/20 Python
在cmd中运行.py文件: python的操作步骤
2018/05/12 Python
解决pycharm每次新建项目都要重新安装一些第三方库的问题
2019/01/17 Python
Python和Java的语法对比分析语法简洁上python的确完美胜出
2019/05/10 Python
树莓派3 搭建 django 服务器的实例
2019/08/29 Python
Ralph Lauren英国官方网站:Ralph Lauren UK
2018/04/03 全球购物
Europcar美国/加拿大:预订汽车或卡车租赁服务
2018/11/13 全球购物
掌上明珠Java程序员面试总结
2016/02/23 面试题
演讲比赛获奖感言
2014/02/02 职场文书
森林防火工作方案
2014/02/14 职场文书
婚纱摄影师求职信
2014/03/07 职场文书
房屋买卖委托书格式范本格式
2014/10/13 职场文书
特岗教师个人总结
2015/02/10 职场文书
党支部季度考核意见
2015/06/02 职场文书
排查Tomcat进程假死的问题
2022/05/06 Servers