学编程这么久,还傻傻分不清什么是方法(method),什么是函数(function)?...

本文深入探讨了Python中方法(method)与函数(function)的区别,通过inspect库的ismethod()和isfunction()函数,揭示了什么情况下一个对象被视为方法或函数。文章指出,用户定义的函数与内置函数在判断上的差异,以及类方法与静态方法在方法判定上的区别。
部署运行你感兴趣的模型镜像

点击上方“编程派”,选择设为“设为星标”

优质文章,第一时间送达!

作者:豌豆花下猫

来自:Python猫 

链接:https://mp.weixin.qq.com/s/e6rIc-dPhbqWAeJvekawwQ

在编程语言中有两个很基础的概念,即方法(method)和函数(function)。如果达到了编程初级/入门级水平,那么你肯定在心中已有了初步的答案。

也许在你心中已有答案了

除去入参、返回值、匿名函数之类的正确的形式内容之外,你也许会说“函数就是定义在类外面的,而方法就是定义在类里面的,跟类绑定的”。

这种说法有没有问题呢?当然有!不然我就不会专门写这篇文章了,本文主要会来厘清这个问题。

在标准库inspect 中,它提供了两个自省的函数,即 ismethod() 和 isfunction(),可以用来判断什么是方法,什么是函数。

因此,本文想要先来研究一下这两个函数,看看 Python 在处理方法/函数的概念时,是怎么做的?

关于它们的用法,先看一个最简单的例子:

运行的结果分别是“True”和“False”,表明我们所定义的 test() 是一个函数,而不是一个方法。

这两个函数也可以用来检测自身,不难验证出它们都是一种函数:

那么,接下来的问题是:inspect 库的两个函数是什么工作原理呢?

先来看看 inspect 中的实现代码:

在源码中,我们看到了 isinstance() 函数,它主要用于判断一个对象(object)是否是某个类(class)的实例(instance)。

我们还看到了 types.FunctionTypetypes.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() 等看起来像是函数的,其实不然:

2、一个类的静态方法,在 ismethod() 眼里并不是方法(MethodType)!

创建了类的实例后,再看看:

可以看出,除了 classmethod 之外,只有类实例的实例方法,才会被 ismethod() 判定为真!而静态方法,不管绑定在类还是实例上,都不算是“方法”!

有没有觉得很不可思议(或者有点理不清了)?

好了,回到本文开头的问题,我们最后来小结一下吧。

若以 inspect 库的两个函数为判断依据,则 Python 中的“方法与函数”具有一定的狭义性。在判断什么是函数时,它们并不把内置函数计算在内。同时,在判断什么是方法时,并非定义在类内部的都算,而是只有类方法及绑定了实例的实例方法才算是“方法”。

也许你会说,inspect 的两个判断函数并不足信,内置函数也应该算是“函数”,类里面的所有方法都应该算是“方法”。

我承认这种说法在广义上是可接受的,毕竟我们一直叫的就是“XX函数”、“XX方法”嘛。

但是,理论和广义概念只是方便人们的沟通理解,而代码实现才是本质的区别。也就是说,Python 在实际区别“方法与函数”时,并不是文中开头的简单说法,还有更多的细节值得关注。

回复下方「关键词」,获取优质资源

回复关键词「 pybook03」,立即获取主页君与小伙伴一起翻译的《Think Python 2e》电子版
回复关键词「入门资料」,立即获取主页君整理的 10 本 Python 入门书的电子版
回复关键词「m」,立即获取Python精选优质文章合集
回复关键词「book 数字」,将数字替换成 0 及以上数字,有惊喜好礼哦~
题图:pexels,CC0 授权。

您可能感兴趣的与本文相关的镜像

Facefusion

Facefusion

AI应用

FaceFusion是全新一代AI换脸工具,无需安装,一键运行,可以完成去遮挡,高清化,卡通脸一键替换,并且Nvidia/AMD等显卡全平台支持

<think> 问题:Python中带点的编程语句风格属于什么类型? 回答:这种风格称为“点表示法”(dot notation)或“点语法”(dot syntax),是面向对象编程中“方法调用”和“属性访问”的标准方式。 详细解释: 1. 点表示法的本质:通过对象访问其成员(属性和方法) - 结构:`对象.成员` - 例如:`df.drop_duplicates()` 中,`df`是一个DataFrame对象,`drop_duplicates`是它的方法 2. 面向对象编程(OOP)的特性: - 封装:将数据和操作封装在对象中 - 点表示法是访问封装内容的标准方式 3. Python中的具体应用: - 模块引用:`import pandas as pd; pd.DataFrame()` - 方法调用:`"text".strip()` - 属性访问:`df.shape` 4. 对比其他编程语言的类似语法: - Java/C#:同样使用点表示法(如:`object.method()`) - JavaScript:也广泛使用点表示法 示例代码说明: ```python # 创建一个字符串对象 s = " Hello World " # 使用点语法调用方法 trimmed = s.strip() # 调用字符串对象的strip方法 print(trimmed) # 输出: "Hello World" # 使用点语法访问属性(以列表对象为例) lst = [1, 2, 3] length = lst.__len__() # 实际中更常用len(lst),这里演示属性访问 print(length) # 输出: 3 ``` 5. 技术术语: - 正式名称:**属性引用**(Attribute Reference) - Python文档定义:`.` 是属性引用运算符,用于访问对象的命名空间中的属性 6. 底层实现原理: - 当执行 `obj.attr` 时,Python解释器会: 1. 检查对象的类定义 2. 在类的 `__dict__` 中查找属性名 3. 如果找到则返回,否则触发 `AttributeError` 7.函数编程的区别: - 函数式风格:`function(obj, args)` - 面向对象风格:`obj.method(args)` - 两种风格在Python中可以并存 §§相关问题§§: 1. Python的点语法在继承机制中如何工作? 2. 如何动态获取对象的属性和方法? 3. 点语法和链式调用有何关联? 4.Python中重写`__getattr__`方法有什么作用? </think> ### Python 中带 `.` 的编程语句风格解析 这种编程风格属于**面向对象编程 (OOP)** 中的**点表示法 (dot notation)** 或**属性访问语法**。它是 Python 面向对象特性的核心组成部分,用于访问对象的属性和调用方法。 #### 详细解释 1. **面向对象编程范式**: - `.` 语法用于访问对象(类实例)的成员(属性和方法) - 表示"属于"关系:`对象.成员` 表示访问该对象的成员 - 符合封装原则:数据和方法绑定在对象内部 2. **点表示法的具体应用**: ```python # 访问属性 person = Person() person.name = "Alice" # 设置属性 print(person.age) # 获取属性 # 调用方法 text = "Hello World" print(text.upper()) # 调用字符串对象的方法 # 访问嵌套对象 import pandas as pd df = pd.DataFrame() df.columns.tolist() # 访问df的columns属性,再调用其方法 ``` 3. **技术术语**: - **属性引用 (Attribute Reference)**:Python 官方术语 - **点运算符 (Dot Operator)**:`.` 符号本身 - **方法调用语法 (Method Invocation Syntax)**:当 `.` 后跟括号时 - **链式调用 (Method Chaining)**:连续使用多个 `.` 调用 4. **与其他编程范式的对比**: | 编程范式 | 访问方式 | 示例 | |----------|----------|------| | 面向过程 | 函数调用 | `len(my_list)` | | 函数式 | 函数组合 | `map(filter(f, data), g)` | | 面向对象 | 点表示法 | `my_list.append(5)` | 5. **Python 中的特殊应用**: ```python # 模块访问 import math print(math.pi) # 访问模块属性 # 类方法调用 class MyClass: @classmethod def class_method(cls): print("Called class method") MyClass.class_method() # 通过类对象调用 # 动态属性访问 obj = SomeObject() attr_name = "value" print(getattr(obj, attr_name)) # 等效于 obj.value ``` #### 底层原理 - Python 中所有对象都有一个 `__dict__` 属性存储成员 - 当执行 `obj.attr` 时,Python 解释器: 1. 检查对象实例的 `__dict__` 2. 检查对象所属类的 `__dict__` 3. 检查继承链中的基类 4. 尝试调用 `__getattr__()` 特殊方法 5. 如果未找到则引发 `AttributeError` #### 优点与最佳实践 **优点**: - 代码组织更清晰 - 支持自动补全和类型提示 - 便于封装和数据隐藏 - 支持方法链式调用 **链式调用示例**: ```python # Pandas 中的链式调用 (df.sort_values('date') .groupby('category') .agg({'value': 'mean'}) .reset_index()) ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值