代码块可以使得一段python代码作为一个单元、一个整体执行。以下是 官方手册 的描述。
所以,有以下几种类型的代码块:
- 模块文件是一个代码块
- 函数体是一个代码块
- class的定义是一个代码块
- 交互式(python idle)的每一个命令行都是一个独立的代码块
- 脚本文件是一个代码块
- 脚本命令是一个代码块(python -c “xxx”)
- 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=2000
z1=2000
print(x is z) # False
print(z is z1) # True
f1()
python先读取x=2000
,并在内存中创建一个属于全局作用域的2000数据对象,再解释y=2000
的时候,发现这个全局对象2000已经存在了(因为x和y同处于全局代码块内),所以不会再额外创建新的2000对象。这里反映出来的结果是"同一个代码块内,虽然仍然是读一行解释一行,但在退出这个代码块之前,不会忘记这个代码块中的内容,而且会统筹安排这个代码块"。
同理def f1()
内的代码块,因为z是本地作用域的变量,更标准的是处于不同代码块内,所以会在本地作用域内存区创建新的数据对象2000,所以x is z
返回False。根据前面的解释,z1 is z
返回True。
再回顾python3作用域中例3:
x= 1
def func():
print x
x= 2
print func()
报错信息:
UnboundLocalError: local variable 'x' referenced before assignment
当执行到def语句的时候,因为def声明函数,函数体是一个代码块,所以按照代码块的方式读取属于这个代码块中的内容。首先读取print(x)
,但并不会直接解释,而是会记住它,并继续向下读取,于是读取x=4
,这意味着x是一个本地变量。然后统筹安排整个代码块,将print(x)
的x认为是本地变量而非全局变量。注意,直到def退出的时候都还没有进行x的赋值,而是记录了本地变量x,赋值操作是在函数调用的时候进行的。当调用函数func()
的时候,发现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=3
print(x is y) # True
f1()
原文链接:https://www.cnblogs.com/f-ck-need-u/asp/9925021.html#%E4%BB%A3%E7%A0%81%E5%9D%97%E7%BB%86%E8%BF%B0%E5%BF%85%E7%9C%8B