Python单行运行、多行运行、可变对象与不可变对象的坑

Python的单行运行、多行运行、可变对象与不可变对象的坑

前提:

参考书:《Python疯狂讲义》、《Python学习手册(第4版)》、菜鸟教程等


1 Python 单行运行、多行运行问题

(1)在使用pycharm时,整个py文件运行很简单,但想运行函数内的单行、类内的单行,建议操作:

  • 选择局部代码进行运行;
  • 选中需要运行的代码;
  • 右键,选择Execute Selection in Console,即可运行。

(2)在命令行窗口下时,单行运行正常操作;但想运行函数/多行运行,建议使用;\。以下举个例子。

在这里插入图片描述

(3)为什么是使用;\呀?
这是因为命令窗口下使用;可以让Python解释器识别出这一行代码结束,表示分隔代码的意思。而\为转义字符,这里可以让Python解释器知道要交互的代码块还没有结束。


2 可变对象和不可变对象

  • 不可变对象(变量指向的内存的中的值不能够被改变):当更改该对象时,由于所指向的内存中的值不可改变,所以会把原来的值复制到新的空间,然后变量指向这个新的地址。python中数值类型(int、float),布尔型 bool,字符串 str,元组 tuple 都是不可变对象。

  • 可变对象(变量指向的内存的中的值能够被改变):当更改该对象时,所指向的内存中的值直接改变,没有发生复制行为。python中列表 list,字典 dict,集合 set都是可变对象。包括自定义的类对象也是可变对象。

  • python变量保存的是对象的引用,这个引用指向堆内存里的对象,在堆中分配的对象分为两类,一类是可变对象,一类是不可变对象。不可变对象的内容不可改变,保证了数据的不可修改(安全,防止出错),同时可以使得在多线程读取的时候不需要加锁。

() is ()     # 返回True,因为tuple是不可变对象(不可改变)
'' is ''     # 返回True,因为str是不可变对象
None is None # 返回True,None也是不可变的
[] is []    # 返回False,因为是可变对象(可能改变,定义出来的两个必然要不一样)
{
    
    } is {
    
    }    # 返回False,因为是可变对象
[] == []    # 返回True,注意==和is的不同,==只比较内容,is比较地址(id)

class Student:  
    pass
Student() is Student()  # 返回False,自定义类型也是可变对象,两次定义的对象地址是不同的

id(Student()) == id(Student())  # 返回True,这里比较神奇。这是因为创建一个Student对象,id()后返回地址但是进行了对象销毁,第二次又重新创建,两次占用了同一个地址

3 Python不可变对象的编译时驻留

(类似java的常量池)

使用java的开发者、学习者,可以回忆回忆JVM的常量池

int 的驻留:-5到256之间的整数都会进行驻留,再次定义的变量地址不变,为什么是-5到256呢,这是解释器决定的,依赖于具体实现。str的驻留:只包含字母,数字,下划线的字符串会驻留;长度为0或1的会驻留;

a = -5    
b = -5   
a is b     
# True,-5到256之间的整数,驻留(因为这部分数据会频繁调用,驻留可以节省资源)
r
a = 256    
b = 256   
a is b     
# True,-5到256之间的整数,驻留

a = -6    
b = -6   
a is b     
# False,非-5到256之间的整数,不驻留

a = 257    
b = 257   
a is b     
# False,非-5到256之间的整数,不驻留

a = 'hello_world'    
b = 'hello'+'_'+'world'
a is b     
# True,只包含字母,数字,下划线的字符串会驻留

a = 'hello_world!'    
b = 'hello_world!'
a is b     
# False,包含了特殊字符!, 不驻留

'hello_world' is '_'.join(['hello', 'world'])     
# False,因为驻留是编译阶段发生的,join在解释阶段才产生结果,未进行驻留

a, b = 'hello_world!', 'hello_world!'
a is b 
# True 编译器的优化,在同一行赋值字符串时,只创建一个对象,指给两个引用。
#(ps:不适用3.7.x以下版本,3.7.x以下中会返回False,建议使用Python3.8.x)

4 关于Python 驻留的坑

4.1 Python 驻留的现象

跟驻留没有直接关系,是(1)命令行窗口单行交互式、(2)命令行窗口函数式、(3).py文件内;这3种情况。

(1)既然python的整型-5到256之间的整数都会进行驻留,非-5到256之间的整数不驻留,且其目的是为了提高效率。那么就这里开始探索:

在这里插入图片描述

可以看出在(1)命令行窗口单行交互式 中-5到256之间的整数都会进行驻留,其(-5到256)之外为False, 被显示出来。

在这里插入图片描述

可以看出在(2)命令行窗口函数式中-5到256之间的整数都会进行驻留,其之外为True,也没有被显示出来

在这里插入图片描述

这里用了菜鸟的在线编译,而Pycharm的如下:

# 将函数放进.py文件里面结果为True
def func():    
	a = 257  
	b = 257  
	return a is b
func()  
# 返回True

可以看出在(3).py文件内中-5到256之间的整数都会进行驻留,其之外为True,也没有被显示出来

4.2 出现Python 驻留的坑的原因

  • 在命名行窗口下运行代码,是交互式,而且是一行一行解释,但for、while、函数调用等一起解释,形成的机器指令可以简单理解为一体。

  • 是python的代码块机制导致的。在同一代码块中相同值的赋值会指向同一个对象。函数体,类对象体,py文件,模块都可以看作一个代码块,导致在命令行窗口单行交互式下跟命令行窗口函数式、py文件内不一样。

  • 在交互式命令行上,一行看作一个代码块,所以,这里所谓“代码块的优化”,就是前面提到的,同行赋值的优化,只在一行(代码块)上优化。

  • 到具体直接运行py文件,又有了更大范围的代码块的优化,所以连着两行相同赋值的对象,会指向同一个对象。

猜你喜欢

转载自blog.csdn.net/xu_yushu/article/details/124615970