IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> 深入理解Python函数中的self -> 正文阅读

[Python知识库]深入理解Python函数中的self

深入理解Python函数中的self

其实应该换个题目: 为什么类定义方法有self但实例调用方法没有self?

理解一等公民: 函数

在Python中一切皆对象, 类是对象, type是对象, 当然函数(方法)也是对象. 对象都有地址, 用id(对象)获得, 判断变量所指对象是不是同一个, 用表达式id(变量1)==id(变量2)判断.

看网上博客经常说, “在实例调用方法时, Python解释器内部把self替换成实例本身了”. 我们试着用函数是一等公民的思想来理解这句话, “实例的方法和类中定义的方法是用一个, 当方法执行是, 解释器会判断是不是实例, 如果是实例那么把方法中的第一个参数默认换成它本身”. 下面来验证这样对不对

class Foo:
    def echo(x):
        print(x)

f1 = Foo()
f2 = Foo()

print(id(f1.echo)==id(Foo.echo))
# False

print(id(f1.echo)==id(f2.echo))
# False

从结果发现, 类定义的函数和实例的函数根本不是同一个, 甚至每个实例的函数都不是同一个. 不是同一个代表了什么? 来看一下特殊的实例方法staticmethod

class Foo:
    @staticmethod  # 静态方法
    def sm(): print('sm')
f1 = Foo()
f2 = Foo()
print(id(Foo.sm) == id(f1.sm) == id(f2.sm)) # True

得到了截然相反的结果, 静态方法在类中和实例中都是同一个. 因为这它的执行不需要实例的参与. 所以, 为了实现实例中普通方法默认第一个参数是实例本身这个语法糖(完全可以看作是一种语法糖), 在类生成实例的同时, 根据类函数生成对应的实例函数(因为函数对象改变了, 所以一定是生成了一个新的函数对象), 并组装在实例身上. 制造一个新函数, 将实例本身保存起来, 将函数作为一等公民的Python实现起来并不难, 一个闭包就可以, 下面来模拟一下

模拟实例组装

from functools import wraps
# 定义一个空壳类
class Foo: pass
# 假设echo是Foo的函数
def echo(self,a):
    print(self.__class__.__name__, a)

# 获取实例函数, 用闭包把实例本身存起来
def get_instance_func(new_instance, class_func):
    @wraps(class_func):
    def instance_func(*arg,**kwargs)
        class_func(new_instance, *arg, **kwargs)
    return instance_func

# 生成实例
def new_foo():
    # 通过object生成新实例
    new_foo_instance = object.__new__(Foo)
    instance_echo = get_instance_func(new_foo_instance, echo)
    # 将新方法组装上
    setattr(new_foo_instance, instance_echo.__name__,instance_echo)
    # 执行初始化方法
    Foo.__init__(new_foo_instance)
    return new_foo_instance

# 测试
foo = new_foo()
foo.echo(10)
# Foo 10

后记

本文目的是探讨和理解Python实例方法省略self实现方法, 当然Python内部肯定不是这样实现的, 但实例方法是新方法, 那么实现思路大同小异, 都是将实例本身储存在实例方法中. 官方文档中写着实例方法用__self__属性保存实例本身, 同时还用__func__保存类中定义的方法. 只不过在上述模拟过程, 用闭包保存, 道理类似.

当然, 以上纯粹是根据代码运行结果的猜测, 如有你有不同的看法, 欢迎交流!

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2022-02-22 20:32:43  更:2022-02-22 20:34:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 0:50:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码