python 变量与常量,赋值指向 与回收
1 变量与常量
变量###
在计算机进程中,变量不仅可以是数字,还可以是任意数据类型。
a = 1
变量a是一个整数。
t_007 = 'T007'
变量t_007是一个字符串。
Answer = True
变量Answer是一个布尔值True。
a = 123 # a是整数
print(a)
a = 'ABC' # a变为字符串
print(a)
变量赋值的意义
方便多次使用
可以修改指向的内容
动态语言与静态语言
和静态语言相比,动态语言更灵活
变量本身类型不固定的语言称之为动态语言 如python。静态语言在定义变量时必须指定变量类型,如果赋值的时候类型不匹配,就会报错。
Java 静态类型
int a = 123; // a是整数类型变量
a = "ABC"; // 错误:不能把字符串赋给整型变量
变量在计算机内存中的表示
创建的过程 + 指向(引用)的过程
a = ‘hello’时,在内存中创建了一个’ABC’的字符串;
在内存中创建了一个名为a的变量,并把它指向’ABC’。
a = 'hello'
b = a
a = 'XYZ'
print(b)
常量
常量就是不能变的变量。
在Python中,通常用全部大写的变量名表示常量
PI=3.1415...
2 赋值引用与垃圾回收
Python是动态类型的语言,赋值的时候对象和引用分离
即先创建对象后引用
a=1
Python的内置函数id()
身份信息id–内存地址
a = 1
b = 1
print(id(a)) 11246696
print(id(b)) 11246696
即 a,b 是指向同一个对象的两个引用
is 用来判断两个变量的指向是否一致
注意: python 缓存 数字 和 短字符串, 长字符串和其他数据类型 会生成新的对象
# a='apple'
# b='apple'
# print(a is b)
# print(id(a),id(b))
# True
# 5812440 5812440 短字符
# m=1
# n=1
# print(m is n)
# print(id(m),id(n))
# True
# 1486795840 1486795840 数字
# x='very good morning'
# y='very good morning'
# print(x is y)
# print(id(x),id(y))
# False
# 32008784 36101768 长字符
x='very good morning'
y='very good morning'
print(x is y)
False
print(id(x),id(y))
32008784 36101768 其它数据类型
应用计数与垃圾回收
在Python中,每个对象都有存有指向该对象的引用计数(reference count)
from sys import getrefcount
m = [1,2]
print(getrefcount(m)) #2 1+1
n = m
print(getrefcount(n)) # 3 2+1
# 在使用 getrefcount的时候 变量作为参数 传进去,会多一次引用
引用计数是 Python采取了一种相对简单的垃圾回收机制,可以有效的释放内存
引用环—影响垃圾回收
两个对象可能相互引用,从而构成所谓的引用环(reference cycle)
a = []
b = [a]
a.append(b)
减少引用
del关键字
from sys import getrefcount
a = [1, 2, 3]
b = a
print(getrefcount(b))
del a
print(getrefcount(b))
重新赋值定向
a = [1, 2, 3]
b = a
print(getrefcount(b))
a = 1
print(getrefcount(b))
垃圾回收
当某个对象的引用计数降为0时,没有任何引用指向时,该对象就成为要被回收的垃圾了
a = [1, 2, 3]
del a 删除 a后,没有任何引用指向之前建立的[1, 2, 3]。用户不可能通过任何方式接触或者动用这个对象。当垃圾回收启动时,Python扫描到这个引用计数为0的对象,就将它所占据的内存清空。
频繁的垃圾回收降低Python的工作效率
垃圾回收时,Python不能进行其它的任务。频繁的垃圾回收将大大降低Python的工作效率。ython只会在特定条件下,自动启动垃圾回收
垃圾回收启动的阈值条件
当Python运行时,会记录其中分配对象(object allocation)和取消分配对象(object deallocation)的次数。当两者的差值高于某个阈值时,垃圾回收才会启动。
gc模块的get_threshold()方法
import gc
print(gc.get_threshold()) #(700, 10, 10)
700即是垃圾回收启动的阈值
可以使用 set_threshold()方法重新设置
两个10是与分代回收相关的阈值
分代回收
Python同时用分代(generation)回收的策略。进程运行过程往往会产生大量的对象,许多对象很快产生和消失,但也有一些对象长期被使用。存活时间越久的对象,存在的意义价值可能越高。
(注意引用环的影响)
python 对象的分代
Python将所有的对象分为0,1,2三代。新建对象都是0代对象。当某一代对象经历过垃圾回收,依然存活,那么它就被归入下一代对象。
垃圾回收启动时,一定会扫描所有的0代对象。如果0代经过一定次数垃圾回收,那么就启动对0代和1代的扫描清理。当1代也经历了一定次数的垃圾回收后,那么会启动对0,1,2,即对所有对象进行扫描。
这两个次数即上面get_threshold()返回的(700, 10, 10)返回的两个10。也就是说,每10次0代垃圾回收,会配合1次1代的垃圾回收;而每10次1代的垃圾回收,才会有1次的2代垃圾回收。
同样可以用set_threshold()来调整,比如对2代对象进行更频繁的扫描。
import gc
gc.set_threshold(700, 10, 5)
为了回收这样的引用环,Python复制每个对象的引用计数,可以记为gc_ref。假设,每个对象i,该计数为gc_ref_i。Python会遍历所有的对象i。对于每个对象i引用的对象j,将相应的gc_ref_j减1。
在结束遍历后,gc_ref不为0的对象,和这些对象引用的对象,以及继续更下游引用的对象,需要被保留。而其它的对象则被垃圾回收。