[Python学习日记-14] Python中基础语法的补充
变量增删改的过程
变量的指向关系
垃圾回收机制
身份运算和None
三元运算
变量增删改的过程
一、增
现在我们假设要创建一个变量名为 name 并且我们要赋它一个值“Jove”,那我们很自然会想到下面的代码
name = "Jove"
print(id(name))
执行这行代码后 Python 就会在内存当中开辟一个空间用于储存这个变量和这个变量值,当然开辟出来的内存空间都会有一个内存地址,有点类似于图书馆的书本编号,这样可以极大地方便我们后面对变量的调用与变量之间的指向
而我们在创建的过程中其实就已经自动的把变量 name 和“Jove”的内存地址进行了指向,当我们在程序中调用 name 时将会先找到 变量名为 name 的变量,然后根据该变量指向的内存地址找到“Jove”,如下图所示
二、删
当使用 del 来删除变量时,其实并不会删除变量所指向内存空间中的内容的,而是先断开该变量指向内存地址的链接,然后再删除变量,换句话说就是只把门口拆了,不让程序进行访问,代码如下
del name2
print(id(name2)) # 由于不存在了,所以会报错
如下图所示,可以看出在 del 了 name 变量后当我们重新指向同样的内容时,Python 会指向回同样的内存地址,可以看出只是访问路径没了,但是东西依然是在的,如果这个访问路径一直没有,编译器中的垃圾回收机制将会将该内存空间回收
三、改
很多时候我们都会需要修改变量,那么 Python 是如何执行的呢,我们执行下面的代码来修改变量 name 的值
name = "Kerry"
在我们理解的修改里面是把原来的删除,然后填入新的值,其实 Python 并不会这样处理,而是会直接开辟一个新的内存空间用来存“Kerry”,之后再断开原来指向“Jove”的链接,最后把变量 name 指向“Kerry”所在的内存地址,而原来的“Jove”在没有变量指向的情况下将会由 Python 中的垃圾回收机制进行自动回收
变量的指向关系
在程序开发的过程中很多时候我们会用到变量给变量赋值的这种操作,就像下面代码那般操作
name1 = "Jove"
name2 = name1
print(id(name1),id(name2))
我们通常会认为 name2 ——> name1 ——> “Jove”的内存地址,那 Python 是这样操作的吗?那我们只要修改 name1 看看 name2 的指向是否有改变就知道了
name1 = "Kerry"
print(id(name1))
我们会发现 name2 并没有跟随 name1 的改变而改变,这就说明了并不是我们刚开始所想的,而是 name2 是直接指向“Jove”的内存地址的
而当改变 name1 的内容时就会断开一开始和“Jove”的链接,然后指向新创建的“Kerry”的内存地址
垃圾回收机制
Python 中的解释器有自动垃圾回收机制,自动隔一段时间把没有跟变量名关联的内存数据回收。该机制主要通过引用计数和循环垃圾收集来实现。回收时间不到1秒,并且可以通过调整解析器的参数来修改这一回收时间。
引用计数是最基本的垃圾回收机制。每个对象都有一个引用计数,当一个对象被引用时,其引用计数加1;当一个对象不再被引用时,其引用计数减1。当一个对象的引用计数变为0时,Python 认为该对象不再被使用,便会将其占用的内存回收。
循环垃圾收集是一种辅助的垃圾回收机制。它会检测并回收那些引用计数不为0,但已经无法被访问到的对象。Python 中的循环垃圾收集采用了标记 - 清除算法。它从一组根对象开始,递归遍历所有可达对象,并对可达对象进行标记。然后,未被标记的对象即被认为是不可达的对象,会被回收。
Python 还有其他一些垃圾回收机制,如分代回收和引用追踪。分代回收是一种根据对象的存活时间将内存分为不同代的垃圾回收机制。引用追踪是一种追踪对象之间相互引用关系的垃圾回收机制。
总的来说,Python 的垃圾回收机制通过引用计数和循环垃圾收集来自动管理和回收内存。这种机制使得开发者可以专注于业务逻辑,而不用过多关注内存管理的细节。
身份运算和None
一、身份运算
Python 中有很多种数据类型,查看一个数据的类型的方法是 type()
name = "Jove"
age = 1
print(name,type(name),type(age))
而判断一个数据类型是不是 str 、int 等数据类型,可以用身份运算符 is
运算符 | 描述 | 实例 |
---|---|---|
is | is 是判断两个标识符是不是引用自一个对象 | x is y,类似 id(x) == id(y),如果引用的是同一个对象返回结果 True,否则返回 False |
is not | is not 是判断两个标识符是不是引用自不同对象 | x is not y,类似 id(a) != id(b),如果引用的不是同一个对象返回结果 True,否则返回 False |
name = "Jove"
print(type(name) is str)
print(type(name) is not int)
二、None
None 在 Python 中代表的意思就是空值(Empty),简单来说就是什么都没有。这个 None 看似在程序当中并没有什么作用,其实并非如此,在变量初始化时是非常有用的,例如游戏创建角色时需要玩家输入名字、年龄、体重、身高,那程序是提前写好的,肯定是需要一个变量来存储玩家输入的数据的,但是在变量创建时如果没有赋值则会报错,这个时候我们就需要赋一个 None 了。换一个思路也可以把 None 当作是一个变量值的占位符,下面我们看一段简单的代码
name = None # 后续需要用户输入
age = None
weight = None
height = Nonename = input() # 用户输入if name is None: # 如果用户没有输入直接回车就进行提示print("你还没有起名字")
从上面的代码可以看出,其实 None 主要还是和身份运算结合使用,当然例子还有很多,这里就不一一列举了。在判断里面 name is None 和 name == None 实现的效果是一样的,只不过使用 == 来判断不符合 Python 的规范,我们学习一门语言最主要就是要遵守它的规范,这样才能真正学成一门编程语言。
三元运算
有这么一个场景有 a = 10,b = 5 而 c 的值若 a 大于15则等于 a 否则等于 b,那么我们使用代码来实现一下
a = 10
b = 5if a > 15:c = a
else:c = b
常规的判断代码需要4行来实现,而三元运算只需要1行就能实现这一判断和赋值
a = 10
b = 5c = a if a > 15 else b # 先读 if a > 15 条件成立执行左边的 c = a,不成立则执行右边
三元运算一眼看下来是挺难读懂的,这是因为它的读法并不是顺序的看,而是跳跃地看的
c = 值1 if 条件A else 值2
如果条件A成立就取左边的 值1,否则取 值2
值得注意的是三元运算只能有一个 if ... else ... 并不能加 else if 进行多次判断