`
java-mans
  • 浏览: 11343381 次
文章分类
社区版块
存档分类
最新评论

[笔记]Python虚拟机的运行时基本知识

 
阅读更多
首先应该了解程序的运行时刻环境,个人觉得龙书中文版第7章挺通俗易懂的。

Python在这方面设计了PyFrameObject这个结构(对应于龙书中的“活动记录”)来维护运行时环境,并采用了“访问链”的思想(龙书中介绍了“访问链”和“显示表”)来解决不同作用域间变量的访问问题。
不过在PyFrameObject中维护了3个成员,用来指向最经常使用的3个符号表,内置符号表、全局符号表、局部符号表:
    PyObject *f_builtins;     /* builtin symbol table (PyDictObject) */
    PyObject *f_globals;      /* global symbol table (PyDictObject) */
    PyObject *f_locals;       /* local symbol table (any mapping) */

这样可以避免在访问全局变量、内建变量时还要通过“访问链”上的回溯来搜索。
PyFrameObject通过如下成员来维护“访问链”(或者称“符号表链”、“名字空间链”):
struct _frame *f_back;    /* previous frame, or NULL */

关于Python的作用域,有一些规则。
最内嵌套作用域规则:由一个赋值语句引进的名字在这个赋值语句所在的作用域里是可见(起作用)的,而且在其内部嵌套的每个作用域里也可见,除非它被嵌套于内部的,引进同样名字的另一条赋值语句所遮蔽/覆盖。
LEGB:符号表的搜索顺序是Local -> Enclosing Function -> Global -> Built-in

一个比较常见而且经典的案例是UnboundLocalError,见如下代码:
x = 10
def foo():
    print(x)
    x += 1
foo()

这一段代码会出现如下错误:
UnboundLocalError: local variable 'x' referenced before assignment

这个问题可以用下面两段话来解答:
This is because when you make an assignment to a variable in a scope, that variable becomes local to that scope and shadows any similarly named variable in the outer scope. Since the last statement in foo assigns a new value tox, the compiler recognizes it as a local variable. Consequently when the earlierprintxattempts to print the uninitialized local variable and an error results.
Otherwise, all variables found outside of the innermost scope areread-only(an attempt to write to such a variable will simply create anewlocal variable in the innermost scope, leaving the identically named outer variable unchanged).

第二个URL,即官方文档也说明了LEGB规则:
  • the innermost scope, which is searched first, contains the local names
  • the scopes of any enclosing functions, which are searched starting with the nearest enclosing scope, contains non-local, but also non-global names
  • the next-to-last scope contains the current module’s global names
  • the outermost scope (searched last) is the namespace containing built-in names


上面讨论了帧对象PyFrameObject和作用域、符号表等,下面是比较大的概念:关于Python虚拟机的运行时环境。

虚拟机的具体实现位于ceval.c中的PyEval_EvalFrameEx函数中。
函数开头首先定义了如下变量:
    register PyObject **stack_pointer;  /* Next free slot in value stack */
    register unsigned char *next_instr;
    register int opcode;        /* Current opcode */
    register int oparg;         /* Current opcode argument, if any */
    register enum why_code why; /* Reason for block stack unwind */

含义可以从注释中看出,比如next_instr表示下一条指令,why表示栈展开的原因。

PyEval_EvalFrameEx是一个非常庞大的函数,拥有庞大的switch/case语句数目来执行各种指令。
函数中提供了几个访问指令的宏:
/* Code access macros */

#define INSTR_OFFSET()  ((int)(next_instr - first_instr))
#define NEXTOP()        (*next_instr++)
#define NEXTARG()       (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2])
#define PEEKARG()       ((next_instr[2]<<8) + next_instr[1])
#define JUMPTO(x)       (next_instr = first_instr + (x))
#define JUMPBY(x)       (next_instr += (x))

此外,在运行时需要涉及的还有线程和进程,Python使用的是系统原生的线程/进程,并使用PyThreadState和PyInterpreterState对象来进行抽象和维护。
在PyEval_EvalFrameEx函数开头,也定义了tstate变量,并把当前线程状态赋值给该变量:
PyThreadState *tstate = PyThreadState_GET();

接着设置线程状态对象中的帧:
    tstate->frame = f;

然后再设置帧的一些信息:
    co = f->f_code;
    names = co->co_names;
    consts = co->co_consts;
    fastlocals = f->f_localsplus;
    freevars = f->f_localsplus + co->co_nlocals;
    first_instr = (unsigned char*) PyString_AS_STRING(co->co_code);
    next_instr = first_instr + f->f_lasti + 1;
    stack_pointer = f->f_stacktop;
    assert(stack_pointer != NULL);
    f->f_stacktop = NULL;       /* remains NULL unless yield suspends frame */

最后,进入switch/case:
        switch (opcode) {

P.S. “访问链”的形成是在PyFrame_New函数中,帧的f_back成员指向当前线程状态对象的frame成员。


JasonLee 2011.08.20 20:18
分享到:
评论

相关推荐

    python学习笔记1

    第一章python是什么跨平台(平台无关性、可移植)、面向对象、脚本语言组成python解释器、字节码编译(.pyc)、python虚拟机(PVM)第二章pyt

    Python学习笔记

    ⾸首先,它会在模块 "载⼊入" 时将源码编译成字节码 (ByteCode)。⽽而后,这些字节码会被虚拟机在⼀一个 "巨⼤大" 的核⼼心函数⾥里解释执⾏行。这是导致 Python 性能较低的重要原因,好在现在有了内置 Just-in-time...

    Python笔记之重学Python,Day2

    Day2 Note 1. 模块   模块是一个包含所有你定义的函数和变量的文件,其后缀名是.py。...  Python是一门基于虚拟机的语言,Python程序的运行过程:   当在命令行输入python xxx.py时,激活Pyth

    python之渗透测试笔记(一)

    python之渗透测试(一)—— Socket模块Socket模块须知简介基本用法使用Socket编写一个简单的服务端和客户端 Socket模块须知 在TCP/IP协议族中,Socket并不是协议,而是一个编程接口。 TCP/IP是传输层协议,主要解决...

    PythonVIS2014:VIS 2014 上的 Python 教程

    Python @ VIS 2014 ... 我们提供了 VirtualBox 来运行虚拟机,但其他虚拟化系统(VMWare、libvirt/qemu 等)应该可以运行镜像。 虚拟机以 OVA(开放虚拟化格式)封装,以便于在您的机器上安装。 在本教程中,如果您

    ml-vm-notebook:机器学习虚拟机(由Vagrant提供)用于构建Spark Notebook应用程序

    Spark虚拟机 用于机器学习/数据科学任务的64位虚拟机。 由Vagrant生成并置备。 该实例基于spark-base64 VM(在Ubuntu 18.04上已经提供了所有必需的软件包)。 最重要的是,它配置并启动Jupyter Notebook进程,并...

    Python全栈自动化测试最新试炼 从技能进阶项目到轻松拿Offer 软件+文档+课件+笔记

    ├─14.python安装.mp4 ├─15.pycharm的安装.mp4 ├─16.fiddler的安装和配置.mp4 ├─17.java的安装和配置.mp4 ├─18.Jenkins的安装和配置.mp4 ├─19.git安装及github注册.mp4 ├─20.node安装.mp4 ├─21....

    《大数据Spark数据处理及python数据结果可视化》学习笔记(另附大作业)

    笔记内容介绍: 第一部分:虚拟机环境 第二部分:大数据处理 第三部分:数据结果可视化 大作业内容介绍: 主要课题:针对北京2013-2017五年内污染物浓度数据进行大数据处理以及结果可视化 包括:数据清洗后的数据集...

    Python笔记

    1、ubuntu虚拟机安装模块 我们以pygame模块为例: 首先需要将自带的python2.x模块换成pyton3.x模块 sudo apt update 更新更新源 sudo apt-get install python3.5 安装 sudo update-alternatives --install /usr/...

    PySystemsManager:一个简单的 Python 脚本,用于通过 SSH 进入盒子并完成任务

    脚本能力视窗将主机添加到 DHCP 和/或 DNS 查看 DHCP 预留添加 AD 用户帐户解锁或禁用 AD 用户帐户查看 Hyper-V 虚拟机Linux 重启服务重新启动或关闭主机笔记对于 Windows 上的 SSH,我一直在使用 。 确保 fab_...

    PythonSIAM2015:SIAM 2015 的 Python 可视化教程

    截至 2015 年 3 月 12 日,虚拟机具有最新的 Anaconda Python 和最新的 ParaView/VTK。 交互式地跟随教程上述链接允许您在 Web 浏览器中进行操作,但无法运行任何代码。 要拥有一个具有交互功能的实时系统,请按照...

    pyprobml:“机器学习:概率视角”的Python代码(第2版)

    如果单击此按钮,它将在运行Google Cloud Platform(GCP)上启动虚拟机(VM)实例。 它已经预安装了您将需要的大多数库(例如scikit-learn,JAX),并使您可以访问免费的GPU。 有关如何使用Colab的详细信息,请参阅...

    Python爬虫学习笔记(那段在win10下安装Docker的不堪回首的往事)

    4.如果你的是Windows家庭版的系统,想用虚拟机,咱还是用Oracle的吧 5.因为“墙”的原因,贫穷的秃头程序员访问不了很多技术、资源网站,但是我们要记得,我们有水木清华,我们有马爸爸,我们有很多同病相怜的同类,...

    JWLS:Wolfram语言脚本的Jupyter笔记本

    运行安装脚本python install.py (位于内核文件夹中) 修改Names.wl.txt中kernel.py的路径,因为它需要完整的路径而不是~ 。 还检查JWLS.sh指向实际的wolframscript可执行文件。 用法 运行JWLS.sh或将其复制到可...

    python笔记(1) 关于我们应不应该继续学习python

    然而,我大学毕业的时候,连linux的虚拟机都没装过,更别提系统熟不熟悉了。虽然我了解一点这个系统可以完全通过命令来操作。后来工作了,有时候写点代码,svn提交上去,服务器是Linux的,自己也是在windows上跑跑...

    python(3.5)学习笔记(n)

    socket用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。 使用socket模块中的socket函数: s = socket.socket(AddressFamily,Type) AddressFamily:可以选择 ① AF_INET...

    run-terraform-inside-aws-codebuild:如何在AWS CodeBuild中运行Terraform

    为什么在AWS Codebuild中运行Terraform 公司中的每个人都可以使用Terraform创建基础架构...您可以构建一个小的Orchestrator,例如在terraform运行之前和之后运行一个python脚本 此示例的步骤 选择一个区域,所有内容都

    java8集合源码分析-CS-Notes-Links:Java开发&计算机基础学习过程中的笔记梳理

    笔记内容大部分都是参考了网上的博客以及书籍,整理笔记的习惯也是刚刚养成的,从开始整理笔记后,发现自己对于做过的东西,能够随着笔记很快的回忆起来,遇到一些问题能够快速从笔记里找到答案也是比较舒服的。笔记...

Global site tag (gtag.js) - Google Analytics