代码块细述(必看)

代码块可以使得一段python代码作为一个单元、一个整体执行。以下是 官方手册 的描述。

A Python program is constructed from code blocks. A block is a piece of Python program text that is executed as a unit. The following are blocks: a module, a function body, and a class definition. Each command typed interactively is a block. A script file (a file given as standard input to the interpreter or specified as a command line argument to the interpreter) is a code block. A script command (a command specified on the interpreter command line with the ‘-c’ option) is a code block. The string argument passed to the built-in functions eval() and exec() is a code block.

所以,有以下几种类型的代码块:

  1. 模块文件是一个代码块
  2. 函数体是一个代码块
  3. class的定义是一个代码块
  4. 交互式(python idle)的每一个命令行都是一个独立的代码块
  5. 脚本文件是一个代码块
  6. 脚本命令是一个代码块(python -c "xxx")
  7. eval()和exec()中的内容也都有各自的代码块

代码块的作用是组织代码,同时意味着退出代码区块范围就退出了作用域范围。例如退出函数区块,就退出了函数的作用域,使得函数内的本地变量无法被函数的外界访问。

此外,python是解释性语言,读一行解释一行,这意味着每读一行就忘记前一行。但实际上更严格的说法是读一个代码块解释一个代码块,这意味着读代码块中的内容时,是暂时记住属于这个代码块中所读内容的,读完整个代码块后再以统筹的形式解释这个代码块。

先说明读一行解释一行的情况,也就是每一行都属于一个代码块,这个只能通过python的交互式工具idle工具来测试:

>>> x=2000
>>> y=2000
>>> x is y
False
>>> x=2000;y=2000
>>> x is y
True

理论上分号是语句的分隔符,并不会影响结果。但为什么第一个x is y为False,而第二个x is y为True?

首先分析第一个x is y。由于交互式工具idle中每一个命令都是一个单独的语句块,这使得解释完x=2000后立刻就忘记了2000这个数值对象,同时忘记的还有x变量本身。然后再读取解释y=2000,因为不记得刚才解释的x=2000,所以会在内存中重新创建一个数值结构用来保存2000这个数值,然后用y指向它。换句话说,x和y所指向的2000在内存中是不同的数据对象,所以x is y为False。

下面的x is y返回True:

>>> x=2000;y=2000
>>> x is y
True

因为python按行解释,一个命令是一个代码块。对于x=2000;y=2000,python首先读取这一整行,发现x和y的数值对象都是2000,于是做个简单优化,等价于x,y=2000,2000,这意味着它们属于一个代码块内,由于都是2000,所以只会在内存中创建一个数据对象,然后x和y都引用这个数据对象。所以,x is y返回True。

idle工具中每个命令都是独立的代码块,但是py文件却是一个完整的代码块,其内还可以嵌套其它代码块(如函数、exec()等)。所以,如果上面的分行赋值语句放在py文件中,得到的结果将是True。

例如:

x = 2000
y = 2000
print(x is y)   # True
def f1():z=2000z1=2000print(x is z)   # Falseprint(z is z1)  # Truef1()

python先读取x=2000,并在内存中创建一个属于全局作用域的2000数据对象,再解释y=2000的时候,发现这个全局对象2000已经存在了(因为x和y同处于全局代码块内),所以不会再额外创建新的2000对象。这里反映出来的结果是"同一个代码块内,虽然仍然是读一行解释一行,但在退出这个代码块之前,不会忘记这个代码块中的内容,而且会统筹安排这个代码块"。

同理def f1()内的代码块,因为z是本地作用域的变量,更标准的是处于不同代码块内,所以会在本地作用域内存区创建新的数据对象2000,所以x is z返回False。根据前面的解释,z1 is z返回True。

再回顾前文多次出现的一个异常:

x = 3
def f1():print(x)x=4
f1()

报错信息:

UnboundLocalError: local variable 'x' referenced before assignment

当执行到def语句的时候,因为def声明函数,函数体是一个代码块,所以按照代码块的方式读取属于这个代码块中的内容。首先读取print(x),但并不会直接解释,而是会记住它,并继续向下读取,于是读取x=4,这意味着x是一个本地变量。然后统筹安排整个代码块,将print(x)的x认为是本地变量而非全局变量。注意,直到def退出的时候都还没有进行x的赋值,而是记录了本地变量x,赋值操作是在函数调用的时候进行的。当调用函数f()的时候,发现print(x)中的x是本地变量,但因为还没有赋值,所以报错。

但是再看下面的,为什么又返回True?

>>> x=256
>>> y=256
>>> x is y
True

因为Python在启动的时候就在内存中预先为常用的较小整数值(-5到256)创建好了对象,因为它们使用的非常频繁(有些在python的内部已经使用了)。所以,对于这个范围内的整数,都是直接引用,不会再在内存中额外创建新的数值对象,所以x is y总是返回true。甚至,这些小值整数可以跨作用域:

x = 3
def f1():y=3print(x is y)   # Truef1()

再看前文循环内的函数的问题。

def f1():for i in range(5):def n():print(i)return nf1()()

前面对现象已经解释过,内部函数n()中print(i)的i不会随循环的迭代而改变,而是固定的值i=4。

python首先解释def f1()的代码块,会记录属于这个代码块作用域内的变量i和n,但i和n都不会赋值,也就是说暂时并不知道变量n是一个函数变量。

同理,当需要解释def n()代码块的时候,将记住这个代码块涉及到的变量i,只不过这个变量i是属于外层函数的,但不管如何,这个代码块记住了i,且记住了它是外部函数作用域的。

注意,函数的声明过程中,所有涉及到变量i的作用域内都不会对i进行赋值,仅仅只是保存了这个i变量名,只有在调用函数的时候才会进行赋值操作

当开始调用f1()的时候,开始执行函数体中的代码,于是开始循环迭代,且多次声明函数n(),每一次迭代生成的n()都会让原先已记录的变量n指向这个新声明的函数体(相当于赋值的操作,只不过是变量n引用的对象是函数体结构,而不是一般的数据对象),由于只是在循环中声明函数n(),并没有进行调用,所以不会对n()中的i进行赋值操作。而且,每次循环迭代都会让变量n指向新的函数体,使得先前迭代过程中定义的函数被丢弃(覆盖),所以最终只记住了最后一轮循环时声明的函数n(),并且i=4。

当调用f1()()时,表示调用f1()中返回的函数n(),直到这个时候才会对n()内的i进行赋值,赋值时将搜索它的外层函数f1()作用域,发现这个作用域内的i指向内存中的数值4,于是最终输出4。

再看下面的代码:

def f1():for i in range(5):def n():print(i)n()return nf1()

输出结果:

0
1
2
3
4

调用f1()的时候,执行循环的迭代,每次迭代时都会调用n(),意味着每次迭代都要对n()中的i进行赋值。

另外注意,前面说过,函数的默认参数是在函数声明时进行赋值的,所以下面的列表L中每个元素所代表的函数,它们的变量i都指向不同的数值对象。

def f1():L = []for i in range(5):def n(i=i):print(i)L.append(n)return Lf1()[0]()
f1()[1]()
f1()[2]()
f1()[3]()
f1()[4]()

执行结果:

0
1
2
3
4

python是解释性语言!相关推荐

  1. python之解释性语言

    目前,常用的解释性语言有 Perl,Python, Lisp/Scheme,Ruby等,究竟什么是解释性语言呢? 所谓的解释性语言主要包括两个方面:以使他们都有自己的解释器,也可以通俗的理解为翻译器: ...

  2. python\java\c\解释性语言\编译性语言 程序执行过程

    c时纯粹的编译性语言,执行过程如下图: 可以看出c是通过预处理器.编译器.汇编器和链接器生成可执行的二进制目标文件,然后直接运行(编译性语言的本质).  Java和python是解释性语言,但并不是纯 ...

  3. python是脚本语言_Python 脚本语言

    python 脚本语言 (python的命名起源于一个脚本screenplay,每次运行都会使对话框逐字重复.由著名的"龟叔"Guido van Rossum在1989年圣诞节期间 ...

  4. python和C++语言哪个难学

    c++难一些,c++兼容c,又在其上加了很多概念,是一个很庞大的重量级语言.但是实际开发中,有些很少用到的.c/c++比较难还在于他们是编译性语言,通常你还需要对编译器有些了解,而不同的平台,编译器是 ...

  5. python 优点_Python语言的优缺点有哪些

    我们参加python培训学习的都知道,这是个比较高薪的编程语言,那么对于它的应用优缺点大家知道多少呢?那我们今天就来该大家分析一下. 优点 1.在python程序来看简单易懂,易于操作,对于初学者来说 ...

  6. Python语言是解释性语言还是编译性语言?

    1.Python语言是解释性语言还是编译性语言? Python语言是先编译再解释的语言.Python 在解释源程序时分为两步: 1:将源码转为字节码 2:将字节码转换为机器码 pyc 文件是由 Pyt ...

  7. python是什么语言开发的-专为人工智能和数据科学而生的Go语言,或将取代Python...

    时间回到30年前,Python 首次亮相.花了20年时间,Python才获得开发者的认可.来到 2019 年,Python已经成为开发人员第二喜欢的语言. 在过去的5年时间里,Python 成为了机器 ...

  8. python语言介绍-Python这门语言的大概介绍

    脚本语言是类似 DOS 批处理.UNIX shell 程序的语言.脚本语言不需要每次编译再执行,并且在执行中可以很容易地访问正在运行的程序,甚至可以动态地修改正在运行的程序,适用于快速地开发以及完成一 ...

  9. python语言属于-python属于解释语言吗

    Python是一门解释型语言? Python是一门解释性语言,我就这样一直相信下去,直到发现了*.pyc文件的存在. 如果是解释型语言,那么生成的*.pyc文件是什么呢?c应该是compiled的缩写 ...

最新文章

  1. 机器学习系列(8)_读《Nature》论文,看AlphaGo养成
  2. 成功解决python\ops\seq2seq.py TypeError: ms_error() got an unexpected keyword argument 'labels'
  3. boost::hana::eval_if用法的测试程序
  4. Linux平台上SQLite数据库教程(二)——C语言API介绍
  5. 初始化linux-nginx的安装和使用
  6. Google 的服务,你用了那些?
  7. 【HTML】建站成功默认页面
  8. Python 3.x中内置函数range()函数的用法
  9. HTTP协议-HTTP权威指南
  10. SQL查询语句基本练习
  11. Tiled Map的使用说明
  12. Mac上最好的白噪音软件:Noizio for Mac
  13. Java、对字符串中的字符排序
  14. 使用JavaScript生成二维码和识别二维码
  15. VLOOKUP函数的使用
  16. android简单计算器源码
  17. 【LEETCODE】【鱼缸难题】
  18. 6步教你zencart模板制作
  19. 华为往事(五)--Camp;C08
  20. 阿里云ECS服务器修复漏洞

热门文章

  1. 8种在JavaScript数组中查找指定元素的方法
  2. Java中获取当前时间
  3. 机械设备行业数字化供应链集采平台解决方案:优化资源配置,实现降本增效
  4. MySQL中Innodb的聚簇索引和非聚簇索引
  5. 工作五年,一年内我靠这系列 java 面试宝典从 13K 到大厂 30K
  6. 公司新来了个00后卷王,一副毛头小子的样儿,哪想到...
  7. (67)TCL脚本命令【incr(一个参数)】
  8. 模电(二)半导体二极管
  9. Learning with Errors
  10. 关于“/usr/include/openssl/bn.h 288 error: parse error before BN_ULONG解决方法