学编程这么久,还傻傻分不清什么是方法(method),什么是函数(function)?
在编程语言中有两个很基础的概念,即方法(method)和函数(function)。如果达到了编程初级/入门级水平,那么你肯定在心中已有了初步的答案。
也许在你心中已有答案了
除去入参、返回值、匿名函数之类的正确的形式内容之外,你也许会说“函数就是定义在类外面的,而方法就是定义在类里面的,跟类绑定的”。
这种说法有没有问题呢?当然有!不然我就不会专门写这篇文章了,本文主要会来厘清这个问题。
在标准库inspect
中,它提供了两个自省的函数,即 ismethod() 和 isfunction(),可以用来判断什么是方法,什么是函数。
因此,本文想要先来研究一下这两个函数,看看 Python 在处理方法/函数的概念时,是怎么做的?
关于它们的用法,先看一个最简单的例子:
运行的结果分别是“True”和“False”,表明我们所定义的 test() 是一个函数,而不是一个方法。
这两个函数也可以用来检测自身,不难验证出它们都是一种函数:
那么,接下来的问题是:inspect 库的两个函数是什么工作原理呢?
先来看看 inspect 中的实现代码:
在源码中,我们看到了 isinstance() 函数,它主要用于判断一个对象(object)是否是某个类(class)的实例(instance)。
我们还看到了 types.FunctionType
及types.MethodType
,它们指的就是目标类。继续点进去看源码:
# 摘自 types.py
def _f(): pass
FunctionType = type(_f)
class _C:
def _m(self): pass
MethodType = type(_C()._m)
这里只是定义了两个空的 _f() 和 _m(),然后就使用了内置的 type() 函数。所以,我们完全可以把它们摘出来,看看庐山真面目:
梳理它们的关系,可以得到:
经过简化处理后,我们发现最关键的是两个问题:type() 函数如何判断出一个对象是 function 或 method 类?instance() 函数如何判断出一个对象是某个类的实例?
这两个内置函数都是用 C 语言实现的,这里我就不打算继续深究了……
但是,让我们再回头看看 inspect 中的注释,就会注意到一些端倪:
- isfunction() 判断出的是用户定义的函数(user-defined function), 它拥有__doc__、__name__ 等等属性
- ismethod() 判断出的是实例方法(instance method), 它拥有函数的一些属性,最特别的是还有一个 __self__ 属性
还是注释更管用啊,由此我们能得到如下的推论:
1、非用户定义的函数,即内置函数,在 isfunction() 眼里并不是“函数”(FunctionType)!
下面验证一下 len()、dir() 和 range():
事实上,它们有专属的类别(BuiltinFunctionType、BuiltinMethodType):
特别需要注意的是,内置函数都是builtin_function_or_method
类型,但是 range()、type()、list() 等看起来像是函数的,其实不然:
(PS:关于这点,我这篇文章 曾提到过,就不再展开了。)
2、一个类的静态方法,在 ismethod() 眼里并不是方法(MethodType)!
创建了类的实例后,再看看:
可以看出,除了 classmethod 之外,只有类实例的实例方法,才会被 ismethod() 判定为真!而静态方法,不管绑定在类还是实例上,都不算是“方法”!
有没有觉得很不可思议(或者有点理不清了)?
好了,回到本文开头的问题,我们最后来小结一下吧。
若以 inspect 库的两个函数为判断依据,则 Python 中的“方法与函数”具有一定的狭义性。在判断什么是函数时,它们并不把内置函数计算在内。同时,在判断什么是方法时,并非定义在类内部的都算,而是只有类方法及绑定了实例的实例方法才算是“方法”。
也许你会说,inspect 的两个判断函数并不足信,内置函数也应该算是“函数”,类里面的所有方法都应该算是“方法”。
我承认这种说法在广义上是可接受的,毕竟我们一直叫的就是“XX函数”、“XX方法”嘛。
但是,理论和广义概念只是方便人们的沟通理解,而代码实现才是本质的区别。也就是说,Python 在实际区别“方法与函数”时,并不是文中开头的简单说法,还有更多的细节值得关注。
看完本文,你有什么想法呢?欢迎一起交流。
学编程这么久,还傻傻分不清什么是方法(method),什么是函数(function)?的更多相关文章
- 学点经济学:M0、M1、M2、M3,傻傻分不清?(转载)
来源:http://t.10jqka.com.cn/pid_97006727.shtml 学点经济学:M0.M1.M2.M3,傻傻分不清? 25,508人浏览 2018-08-03 11:06 常听人 ...
- 2021年了,`IEnumerator`、`IEnumerable`还傻傻分不清楚?
IEnumerator.IEnumerable这两个接口单词相近.含义相关,傻傻分不清楚. 入行多年,一直没有系统性梳理这对李逵李鬼. 最近本人在怼着why神的<其实吧,LRU也就那么回事> ...
- bind,apply,call,caller,callee还傻傻分不清楚?
先介绍每个的语法: 1. bind() 语法:fn.bind(thisObj[, arg1[, arg2[, ...]]]) fn:是想要改变this指向的函数 thisObj:表示fn中this指针 ...
- JDBC、ORM、JPA、Spring Data JPA,傻傻分不清楚?一文带你厘清个中曲直,给你个选择SpringDataJPA的理由!
序言 Spring Data JPA作为Spring Data中对于关系型数据库支持的一种框架技术,属于ORM的一种,通过得当的使用,可以大大简化开发过程中对于数据操作的复杂度. 本文档隶属于< ...
- JS魔法堂:属性、特性,傻傻分不清楚
一.前言 或许你和我一样都曾经被下面的代码所困扰 var el = document.getElementById('dummy'); el.hello = "test"; con ...
- Java:接口和抽象类,傻傻分不清楚?
01. 来看网络上对接口的一番解释: 接口(英文:Interface),在 Java 编程语言中是一个抽象类型,是抽象方法的集合.一个类通过继承接口的方式,从而来继承接口的抽象方法. 兄弟们,你们怎么 ...
- [转帖]十分钟快速理解DPI和PPI,不再傻傻分不清!
十分钟快速理解DPI和PPI,不再傻傻分不清! https://baijiahao.baidu.com/s?id=1605834796518990333&wfr=spider&for= ...
- 【华为敏捷/DevOps实践】7. 敏捷,DevOps,傻傻不分清楚【华为云技术分享】
文:姚冬(华为云DevCloud首席技术布道师,资深DevOps与精益/敏捷专家,金融解决方案技术Leader,中国DevOpsDays社区核心组织者) 前言 敏捷是什么?DevOps是什么?两者有什 ...
- 傻傻分不清之 Cookie、Session、Token、JWT
傻傻分不清之 Cookie.Session.Token.JWT 什么是认证(Authentication) 通俗地讲就是验证当前用户的身份,证明“你是你自己”(比如:你每天上下班打卡,都需要通过指纹打 ...
随机推荐
- Python编程 从入门到实践-3列表下
笔记出处(学习UP主视频记录) https://www.bilibili.com/video/av35698354?p=5 3.2.3 从列表中删除元素-使用del语句删除元素 motorcycles ...
- .net core WebAPI+EF 动态接收前台json,并动态修改数据库
用API开发的人都知道,常用的后台接收参数就是建个DTO,然后前台把这个DTO传过来.后台再更新,例如如下例子: public async Task<IActionResult> PutM ...
- python学习的新篇章--面向对象
面向对象的学习笔记 关键要素: 类:class 用来描述具有相同的属性和方法的对象的集合,它定义了该集合中每个对象所共有的属性和方法. 数据成员: 类的不同属性数据 对象: 类的一个实例 ...
- 计算属性(computed)+侦听器(watch)+ 方法(methods)
计算属性 computed 当数据改变时,方法的结果也会发生改变.如果多处地方调用计算属性里面的同一个方法时,该方法只会执行一次.如图,在控制台改变data里面的num值时,虽然在多处使用comput ...
- 创建Sphinx + GitHub + ReadtheDocs托管文档
最新博客链接 "Tsanfer's Blog" 创建Sphinx + GitHub + ReadtheDocs托管文档 Readthedocs在线电子书链接
- vuepress-theme-reco + Github Actions 构建静态博客,部署到第三方服务器
最新博客链接 Github链接 查看此文档前应先了解,vuepress基本操作 参考官方文档进行配置: vuepress-theme-reco VuePress SamKirkland / FTP-D ...
- JavaScript每日学习日记(1)
8.11.2019 1. lastIndexOf() 方法从尾到头进行检索. 2. 有三种提取部分字符串的方法: 2.1 slice(start, end) 如果某个参数为负,则从字符串的结尾开始计 ...
- jvm 性能调优工具之 jps 命令详解
JPS名称:jps - Java Virtual Machine Process Status Tool命令用法:jps [options] [hostid] options:命令选项,用来对输出格式 ...
- 图解I/O模型
本文带你鸟瞰I/O模型全貌,希望可以让你对I/O模型有一个直观的认识 什么是I/O?I/O的过程?同步阻塞 I/O同步非阻塞 I/OI/O多路复用异步I/O 什么是I/O? I/O就是计算机内 ...
- MyBatis框架——动态SQL
MyBatis 作为⼀个“半⾃动化”的 ORM 框架,需要开发者⼿动定义 SQL 语句. 在业务需求⽐较复杂的情 况下,⼿动拼接 SQL 语句的⼯作量会⾮常⼤,为了适⽤于不同的业务需求,往往需要做很多 ...