5、垃圾回收机制与用户交互以及运算符
一、垃圾回收机制
1.1、什么是垃圾回收机制?
垃圾回收机制是Python解释器自带的一种机能,专门用来回收不可用的变量值所占用的内存空间。
1.2、为什么要有垃圾回收机制?
在程序的运行中,会申请大量的内存空间,造成内存溢出,导致程序崩溃。因此管理内存是一件繁杂的事,所以Python解释器自带的垃圾回收机制能让程序员从中脱离出来。
1.3、垃圾回收机制什么使用?
因为这是在Python解释器后台中执行的,因此不需要去操控他。
二、理解GC垃圾回收机制原理
2.1、堆区和栈区
在定义变量时变量名、变量值都是需要储存的。分别对应在内存中的两个地方栈区以及堆区。
变量名以及值内存地址存放在栈区
变量值存放在堆区,垃圾清理的就是堆区。
2.2、直接引用和间接引用
直接引用指的是变量名直接通过内存地址,由栈区引用到堆区。
例如:a=[10,20]
间接引用指的是变量名由栈区引导到堆区后,再通过下一步引用找到对应的堆区。
例如:a=[b,20]
b=30
这里a会有一个存放在内存的堆区,而后会再找到20和30的堆栈。
2.3垃圾回收机制原理介绍
Python上的GC模块采用“引用计数”来跟踪和回收垃圾;在使用引用计数的基础上,还可以使用“标记清除”解决容器对象可能出现的循环引用问题;并且通过“分代回收”以空间换区时间的方式进一步提高垃圾回收的效率。
2.3.1、引用计数
引用计数是变量值被变量名引用次数的统计。
例如:a = 1,b=a时,1这个值就被引用两次了。这就是引用次数的增加。
当:a=2时,1这个值就只剩b引用了,这就是引用次数的减少。
如果引用次数为0时,就会清除堆栈里面的变量值。
2.3.2、引用计数问题一:循环引用
引用计数有一个致命的问题即循环引用(也称交叉引用)
例如:当断开a1,以及a2的关联时(del a1,del a2),a1与a2的值还在互相引用着,这就会导致引用计数不为0,无法清除。
a1 = [11, ]
a2 = [22, ]
a1.append(a2)
print(a1) #[11, [22]]
a2.append(a1)
print(a2) #[22, [11, [...]]]
然而,由于断开了a1,与a2的关联,所以也找不到这两个对应的值。造成内存永远不会被释放所以python引用了“标记-清除”以及“分代回收来解决这个问题
2.3.2、解决方案:“标记-清除”
“标记-清除”的做法是找到所有栈区里面所有变量名对应堆区的变量值进行标记,当内存空间被耗尽时,停止程序,清除所有堆区未被标记的变量值。从而解决引用计数带来的循环计数问题。
2.3.2、引用计数问题二:效率问题
基于垃圾回收机制每次回收内存,需要将所有对象的引用计数全部扫一遍,十分的消耗时间,因此使用空间换取时间的方法。即分代回收。
2.3.4、解决方案:分代回收
分代回收的核心是通过多次的扫描,部分变量还是没有被清零,因此决定将他们默认为常量,并且减少对这部分变量值的扫描。从而节省时间。
三、Python语法之用户交互
3.1、什么是用户交互
用户交互就是人往计算机中输入数据,计算机根据设定好的结果输出数据。
3.2、为什么需用户交互?
希望计算机能够和人一样进行交流。
3.3、怎么和用户进行交互
交互的本质就是输入以及输出。
3.3.1、输入input
username=input('请输入你的账号:') # 请输入你的账号:
Python3中,所有输入的值都会变成字符串类型。
3.3.2、输出print
只输出一个值:
print('hallo world') # hallo world
输出多个值:
print('a,b,c') # a,b,c
3.3.3、格式化输出
3.3.3.1、什么是格式化输出
将一段字符里面的某些内容替换掉之后输出,称之为格式化输出。
3.3.3.2、为什么要有格式化输出
我们经常会输出一些固定格式的内容,例如:亲爱的XXX你好。我们需要做的就是将XXX替换掉。
3.3.3.3、格式化输出怎么使用
通常使用占位符%d以及%s。%d只能代替数字,%s可以代替任何类型。
3.3.3.3.1、字符串类型使用格式化输出
例如:res='my name is %s my age is %s'%(egon,18)
3.3.3.3.2、字典类型使用格式化输出
例如:res=‘my name is %(name)s my age is %(age)s’ %{'name':'egon','age':18}
3.3.3.3.3.1、使用字符串str.format:兼容性好 建议使用
例如:res='my name is {} my age is {}'.format('egon',18)
也可以:res='my name is {0}{0}{0} my age is {1}{1}'.format('egon',18)
3.3.3.3.3.2、使用字典dict.format
例如:res='my name is {name} my age is {age}'.foemat(name='egon',age=18) #format()内加的是变量。
3.3.3.3.4 填充与格式化
先取到值,然后在冒号后设定填充格式:[填充字符][对齐方式][宽度]
*<10:左对齐,总共10个字符,不够的用*号填充
print('{0:*<10}'.format('开始执行')) # 开始执行******
*>10:右对齐,总共10个字符,不够的用*号填充
print('{0:*>10}'.format('开始执行')) # ******开始执行
*^10:居中显示,总共10个字符,不够的用*号填充
print('{0:*^10}'.format('开始执行')) # ***开始执行***
3.3.3.3.5精度与进制
print('{salary:.3f}'.format(salary=1232132.12351)) #精确到小数点后3位,四舍五入,结果为:1232132.124
print('{0:b}'.format(123)) # 转成二进制,结果为:1111011
print('{0:o}'.format(9)) # 转成八进制,结果为:11
print('{0:x}'.format(15)) # 转成十六进制,结果为:f
print('{0:,}'.format(99812939393931)) # 千分位格式化,结果为:99,812,939,393,931
3.3.3.3.6、f : #python3.5后才推出
x = input('your name: ')
y = input('your age: ')
res = f'我的名字是{x} 我的年龄是{y}'
print(res)
四、运算符
4.1、算数运算符
Python在支持算数运算符上与数学上运用的符号是一致的。
假设变量:a=10,b=20
4.3、比较运算符
通常用来对两个值进行比较,返回的值为Ture或者Flase.。
4.3、赋值运算符
赋值=运算符中除了=号以外,还有增量赋值、链式赋值、交叉赋值、解压赋值。这些赋值方式可以让代码看的更加精简。
4.3.1、增量赋值
4.3.2、链式赋值
可以将一个值同时赋值给多个变量名,例如:
a=1
b=a
c=b
可以写成a=b=c=1
4.3.3、交叉赋值
可以将两个变量对应的变量值进行交换。例如:
m=2
n=3
l=m
m=n
n=l
可以写成:m,n=n,m
4.3.4、解压赋值
可以将列表中多个值取出来赋值给多个变量名,例如:
number=[1,2,3,4,5,]
print(number[0])
print(number[1])
print(number[2])
print(number[3])
print(number[4])
可以直接写成a,b,c,d,e=number
print(number)
在赋值的多个变量名数量无法与列表中的变量名数量一致时,可以使用:
a,b,c,*_=number #只取前面三个值
*_,a,b,c=number #只取后面三个值
字符串、字典、元组、集合类型都支持解压赋值