Python中的变量赋值
作者:真的会了吗 发布时间:2023-07-23 06:00:10
引言:
Python
中的变量在使用中很流畅,可以不关注类型,任意赋值,对于开发来说效率得到了提升,但若不了解其中的机理,往往也会犯一些小错,让开发进行的不那么流畅,本文就是从语言设计和底层原理的角度,带大家理解Python中的变量。
下面我们从一个简单例子开始:
a = 3
当我们代码中写入a=3
时到底发生了啥,从概念上来说,Python
会执行三个不同的步骤来完成这个请求:
创建了一个对象来代表值3
若是a尚未创建会创建一个变量a
将变量a和新的对象3进行关联,称变量a为对象3的一个引用
上文提到的三个关键字,“对象
”、“变量
”、“引用
”是Python
中让变量得以运作的关键,我们在下一小节细细道来。
1 变量、对象、引用
先从概念说起:
对象是分配的一块内存,有足够的空间去表示它们所代表的值。
变量是一个系统表的元素,拥有指向对象的连接的空间。
引用时自动形成的从变量到对象的指针。
接着上文中a=3的三个步骤,咱们增加一句代码:
a = 3
b = a
下面通过一张图表征了两句话执行的结果:
关于b=a
引发的操作为b同样也指向了3,建立了从变量b到对象3的引用,此部分实现了python
的赋值操作。此部分引出了Python中的赋值操作的秘密,下面咱们先来看一下为什么Python中变量赋值时不用指定变量的类型呢,实际上从上面的概念中已经发现了一个重要定义:
>>> 类型属于对象,而不是变量
为了理解对象类型是如何使用的,我们看一下对一个变量多次赋值的结果:
a = 3
a = 'wali'
a = 3.1415926
从表面上看,a开始是一个整数,接着变成一个字符串,最后变成一个浮点,对于学习过C语言的人来说,这个是无法理解的,但对于python
来说,这是可以执行的。看起来像是a的类型在连续改变,实际上我们理解了变量、引用、对象的概念以及“类型属于对象,而不是变量”这些知识后,我们会发现,实际发生了如下的事情:
执行中分别创建了整数类型的对象3,字符串的对象“wali
”以及浮点数的对象3.14,变量a并不拥有这些类型,只是简单的通过引用分别指向了三个对象。
进一步深入研究就会发现,从Python
语言实现的角度来说,每个对象都包含了一个头部信息,其中就标识了这个对象的类型。
此外,还有一个概念“引用计数器”,我们再来看下,最开始的代码:
a = 3
b = a
可能聪明的读者已经心里默默计算出对于对象3的引用计数器的值为2,分别为变量a和变量b对对象3的引用。是的,引用计数器的定义就是这么明了,用于表征用于指向同一个对象的引用的个数。通过变量间的赋值操作,自动的计算对象的引用计数。
那么,我们又会问引用计数器有啥用呢,为啥要多此一举来计算有多少个变量引用同一个变量呢,此时我们引出一个新的概念:对象的垃圾回收。
2 对象的垃圾回收机制
有一段代码:
a = 3
a = 'wali'
a = 3.1415926
我们会进一步思考,当我把a从指向整数对象3改变为指向字符串对象‘wali'
时,那对象3发生了啥 ?难道一直放在内存里,如果对象非常大,那岂不是很占用内存,实际上Python
设计者早就为我们考虑的很周全了:
在Python
中,每当一个变量名被赋予了一个新的对象,之前的那个对象空间就会被回收(前提为此对象没有被其他的变量名或对象所引用),这种自动回收对象空间的技术叫做垃圾回收。
这里如何判断何时回收,就得用到上一节所说的一个非常重要的概念,对象引用计数器,当计数器值为0标识无变量或对象引用,自动回收对象空间。到此,我们明白了对象引用计数器的重要作用,也理解了,除了我们看到的代码,Python
也在默默的为我们做不少自动化的事情。
3 变量所指向的对象不同会有何不同?
#example 1
a = 3
b = a
a = 5
我们回到上面的例子中,如果a发生变化,那么b会跟着发生变化吗?理论上指向同一个对象是会跟着发生变化的,但是这里的答案是不会,因为对象3是数字,不可变对象,所以只能重新创建一个新的对象5,然后a指向对象5,但是如果a所指向的对象是一个可变的对象,比如说列表,就会和我们想的一样b也会跟着发生变化,如下面的例子所示:
#example 2
a = [1,2,3]
b = a
a[0] = 3
L = a is b
>>>True
M = a == b
>>>True
那么看下面的例子,例子2 和例子3 有什么区别呢?
#example 3
a = [1,2,3]
b = [1,2,3]
L = a is b
>>>False
M = a == b
>>>True
在python
中有两种方法检测变量是否相等,is 和 == ,其中==是判断变量所指向的对象的值是否相等,is是判断对象的同一性,如果两个变量精确的指向同一对象,is操作符才会返回True
,也可以理解为is
操作符,是比较实现引用的指针是否相同,例子2中变量a和变量b指向同一个对象,所以L和M都是True
,但是例子三中变量a和变量b指向不同的对象,所以才会出现例子3下面的L和M的值的不一样的情况~但是如果下面的例子又会出现不同的结果:
#example 4
a = 3
b = 3
L = a is b
>>>True
M = a == b
>>>True
#example 5
c = [1,2,3]
K = c[2] is a
>>>True
是为什么呢?因为3 为不可变对象,为了节省内存消耗,只会保留一份,不管有多少个引用指向对象3,对象3都只有一份,例子5也很好的证明了这一点~
例子4和例子5中变量和对象的引用关系
课外小知识:
(1)可变类型,值可以改变:主要包括list列表,dict
字典;不可变类型,值不可以改变:主要包括:数值类型int
、long
、bool
、float
,字符串str
,元组tuple
在例子3中变量a和b的所指向的对象为可变对象,并且a和b的地址不一样,但是a和b中的元素所指向的对象其实是一样的,如下图所示
来源:https://zhuanlan.zhihu.com/p/302399063


猜你喜欢
- 在mysql数据库开发中,我们有时候需要复制或拷贝一张表结构和数据到例外一张表,这个时候我们可以使用create ... select ..
- 这只是自己练习的一个记录而已。因为某种原因,不想用yii自带的user表,想用自己建的admin数据库表,修改如下:1. 参考高级模板里里的
- 最近写了一个软件屡屡打包不能正常运行,而直接在cmd命令行窗口运行却都能正常输出,没有任何报错,一开始怀疑程序里面sys.args[1]使用
- 一、人脸图像特征提取方法https://www.jb51.net/article/219446.htm二、对笑脸数据集genki4k进行训练
- 背景由于 python 自带的源下载速度非常慢,特别是安装一些库的时候,甚至有时会失败。pip国内的一些镜像 阿里云 http:
- 请看下面的操作图解。1.使用Sql Server Management Studio 2008 连接数据库。2.选中要导出数据的数据库节点,
- JavaScript中的字符串函数没有像VBScript\ASP中的内部函数那么全.不能像VB那样直接利用left和right函数来实现对字
- 一: 删除LOG1:分离数据库 企业管理器->服务器->数据库->右键->分离数据库2:删除LOG文件3:附加数据库 企业管理器->服务器-
- 为什么你写的sql查询慢?为什么你建的索引常失效?通过本章内容,你将学会MySQL性能下降的原因,索引的简介,索引创建的原则,explain
- 在 Python/Django 的世界里有这样一个谚语:为语言而来,为社区而留。对绝大多数人来说的确是这样的,但是,还有一件事情使得我们一直
- 要从tablename表中随机提取一条记录,大家一般的写法就是:SELECT * FROM tablename ORDER BY RAND(
- NumPy矩阵和向量矩阵在NumPy中,矩阵可以看作是一个二维数组,其中每个元素都可以通过行列坐标来定位。它表示为一个m×
- 简介这是一个操作数据库(sqlite3)的项目,用PyQt5进行界面封装。此次项目最主要的是,主界面与子界面的交互,一个主界面与三个子界面交
- 前言了解 Python 的都知道 Pyinstaller 可以将 .py 文件打包成 windows 下可执行的 .exe 文件, 但是在我
- 场景当我提交了本次修改到本地和远程分支后,发现我本次提交还少了一些修改内容,或者说本次修改是完全错误的,然而也push到远程仓库去了。如何回
- documentFragment 是一個無父對象的document對象.他支持以下DOM2方法:appendChild, cloneNode
- hypot()方法返回的欧几里德范数 sqrt(x*x + y*y).语法以下是hypot()方法的语法:hypot(x, y)
- 在python中调用fortran代码,要用到f2py这个程序。它的项目主页在此。现在该项目已经合并到numpy中了,先安装python再装
- arange()类似于内置函数range(),通过指定开始值、终值和步长创建表示等差数列的一维数组,注意得到的结果数组不包含终值。linsp
- 引言RunLoop:又叫运行循环机制,在iOS中的两大机制之一。并不是只有iOS有Runloop其他语言也有,他们的方式不太一样,但是核心都