《Python 源码剖析》一些理解以及勘误笔记(2)

2023-12-16 19:32

本文主要是介绍《Python 源码剖析》一些理解以及勘误笔记(2),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

以下是本人阅读此书时理解的一些笔记,包含一些影响文义的笔误修正,当然不一定正确,贴出来一起讨论。

注:此书剖析的源码是2.5版本,在python.org 可以找到源码。纸质书阅读,pdf 贴图。

文章篇幅太长,故切分成3部分,这是第二部分。



p248: 嵌套函数、闭包和 decorator 

co_cellvars: 通常是一个tuple,保存嵌套的作用域内使用的变量名集合;

co_freevars: 通常是一个tuple,保存使用了的外层作用域中的变量名集合。

如下的一段Python 代码:

 Python Code 
1
2
3
4
5
6
7
8
def get_func():
    value =  "inner"
     def inner_func():
         print value
     return inner_func

show_value = get_func()
show_value()

则py 文件编译出来的PyCodeObject 有3个,那么与get_func 对应的对象中的 co_cellvars 就应该包含字符串 "value",而与 inner_func 

对应的PyCodeObject 对象的co_freevars 也应该有字符串"value"。

闭包从创建、传递到使用的全过程可以用以下三幅图演示:




inner_func 可以认为是 get_func 的局部变量,如图2 中 inner_func 对应的 PyFunctionObject 对象的 func_closure 指向 tuple。在inner_func 调用过

程中,tuple 中包含的一个个cell  对象就被放到 f_localplus 中相应的位置,当引用外层作用域符号时,一定是先到 f_localsplus 中的 free 变量区域获

符号对应的值。实际上 value 的值可以通过 show_value.__closure__[0].cell_contents 访问到。使用闭包的时候需要注意返回的函数不要引用任何循环变量,或者后续会发生变化的变量,否则出现的情况可能与你预期不同。


在closure 技术的基础上,Python 实现了 decorator,decorator 可以认为是 "func = should_say(func)" 的一种包装形式。

 Python Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# decorator 实现
def should_say(fn):
     def say(*args):
         print  'say something...'
        fn(*args)
     return say

@should_say
def func():
     print  'in func'

func()
# 输出结果为
# say something...
# in func

# 不用decorator 的实现
...
def func():
     print  'in func'

func = should_say(func)
func()
         

注意还有含参的装饰器(再封装一层),以及装饰类(接收一个类,并返回一个新类)。


p264: Python 中的可调用性(callable)。只要一个对象对应的class 对象中实现了"__call__" 操作(更确切地说,在 Python 内部的 

PyTypeObject 中,tp_call 不为空),那么这个对象就是一个可调用的对象,比如:

class A(object):

def __call__(self): print  'Hello Python'

那么 a= A()   a() 会输出'Hello Python' ;可以认为 PyA_Type 对象的 tp_call 不为空。在 c++ 看来也就是函数对象的实现。

所谓 “调用”,就是执行对象的 type 所对应的 class 对象的 tp_call 操作。


p268: 内置类型对应的PyTypeObject 的tp_dict 填充、descriptor

在Python 内部,存在多种 descriptor,PyType_Ready 在通过add_operators 添加了 PyTypeObject 对象中定义的一些 operator 后,

会通过 add_methods、add_members、add_getsets 添加在PyType_Object 中定义的 tp_methods、tp_members、tp_getset 函数

集。这些 add_*** 的过程与 add_operator 类似,不过最后添加到 tp_dict 中的descriptor 就不再是PyWrapperDescrObject,而分别是

PyMethodDescrObject、PyMemberDescrObject、PyGetSetDescrObject。


注:PyWrapperDescrObject 的 ob_type 是 PyWrapperDescr_Type,PyWrapperDescr_Type 对象中的 tp_call 是wrapperdescr_call,当

Python 虚拟机”调用“一个 descriptor 时,也就会调用 wrapperdescr_call 。

一般而言,对于一个 Python 中的对象obj,如果 obj.__class__ 对应的 class 对象中存在 __get__ 、__set__、__delete__ 三种操作,那么 obj 可以称

为Python 的一个 descriptor。像 PyWrapperDescr_Type 的 tp_descr_get 设置了 wrapperdescr_get,故称  PyWrapperDescrObject 为 descriptor。



如上图来说,实际上 mp_subscript 和 d_wrapped  都是函数指针变量,它们的值相等,都是 list_subscript 。

如下的例子重写了list 的 '__repr__ ' 方法,则初始化完成后的 A 如下图所示:

class A(list):

def __repr__(self): return ‘Python'



即如果没有重写则 A.tp_repr 没有定义,A.tp_dict 里面也没有定义 '__repr__',当 a = A();  a.__repr__()  找到是在mro 列表中某基类定义的 

'__repr__' ,比如 PyList_Type 的 d_wrapped 和 tp_repr 一样,都是 list_repr。

如果重写了则创建时A.tp_repr 被赋值为 slot_to_repr。在 slot_to_repr 中,会寻找 '__repr__' 方法应的 PyFunctionObject 对象,正好就找到在 A 定

义中重写的函数。比如 A.__dict__['__repr__'] 显示是<function  __repr__  at  ...>,而

 

这篇关于《Python 源码剖析》一些理解以及勘误笔记(2)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/501626

相关文章

使用Python删除Excel中的行列和单元格示例详解

《使用Python删除Excel中的行列和单元格示例详解》在处理Excel数据时,删除不需要的行、列或单元格是一项常见且必要的操作,本文将使用Python脚本实现对Excel表格的高效自动化处理,感兴... 目录开发环境准备使用 python 删除 Excphpel 表格中的行删除特定行删除空白行删除含指定

深入理解Go语言中二维切片的使用

《深入理解Go语言中二维切片的使用》本文深入讲解了Go语言中二维切片的概念与应用,用于表示矩阵、表格等二维数据结构,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录引言二维切片的基本概念定义创建二维切片二维切片的操作访问元素修改元素遍历二维切片二维切片的动态调整追加行动态

Python通用唯一标识符模块uuid使用案例详解

《Python通用唯一标识符模块uuid使用案例详解》Pythonuuid模块用于生成128位全局唯一标识符,支持UUID1-5版本,适用于分布式系统、数据库主键等场景,需注意隐私、碰撞概率及存储优... 目录简介核心功能1. UUID版本2. UUID属性3. 命名空间使用场景1. 生成唯一标识符2. 数

Python办公自动化实战之打造智能邮件发送工具

《Python办公自动化实战之打造智能邮件发送工具》在数字化办公场景中,邮件自动化是提升工作效率的关键技能,本文将演示如何使用Python的smtplib和email库构建一个支持图文混排,多附件,多... 目录前言一、基础配置:搭建邮件发送框架1.1 邮箱服务准备1.2 核心库导入1.3 基础发送函数二、

Python包管理工具pip的升级指南

《Python包管理工具pip的升级指南》本文全面探讨Python包管理工具pip的升级策略,从基础升级方法到高级技巧,涵盖不同操作系统环境下的最佳实践,我们将深入分析pip的工作原理,介绍多种升级方... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核

基于Python实现一个图片拆分工具

《基于Python实现一个图片拆分工具》这篇文章主要为大家详细介绍了如何基于Python实现一个图片拆分工具,可以根据需要的行数和列数进行拆分,感兴趣的小伙伴可以跟随小编一起学习一下... 简单介绍先自己选择输入的图片,默认是输出到项目文件夹中,可以自己选择其他的文件夹,选择需要拆分的行数和列数,可以通过

Python中反转字符串的常见方法小结

《Python中反转字符串的常见方法小结》在Python中,字符串对象没有内置的反转方法,然而,在实际开发中,我们经常会遇到需要反转字符串的场景,比如处理回文字符串、文本加密等,因此,掌握如何在Pyt... 目录python中反转字符串的方法技术背景实现步骤1. 使用切片2. 使用 reversed() 函

Python中将嵌套列表扁平化的多种实现方法

《Python中将嵌套列表扁平化的多种实现方法》在Python编程中,我们常常会遇到需要将嵌套列表(即列表中包含列表)转换为一个一维的扁平列表的需求,本文将给大家介绍了多种实现这一目标的方法,需要的朋... 目录python中将嵌套列表扁平化的方法技术背景实现步骤1. 使用嵌套列表推导式2. 使用itert

使用Docker构建Python Flask程序的详细教程

《使用Docker构建PythonFlask程序的详细教程》在当今的软件开发领域,容器化技术正变得越来越流行,而Docker无疑是其中的佼佼者,本文我们就来聊聊如何使用Docker构建一个简单的Py... 目录引言一、准备工作二、创建 Flask 应用程序三、创建 dockerfile四、构建 Docker

Python使用vllm处理多模态数据的预处理技巧

《Python使用vllm处理多模态数据的预处理技巧》本文深入探讨了在Python环境下使用vLLM处理多模态数据的预处理技巧,我们将从基础概念出发,详细讲解文本、图像、音频等多模态数据的预处理方法,... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核