一、垃圾回收机制略解
垃圾回收机制(简称GC)是Python解释器自带的一种机制,专门用来回收不可用(引用次数为0)的变量值所占用的内存空间。
Python的GC模块主要运用了“引用计数”来跟踪和回收垃圾。在引用计数的基础上,还可以通过“标记-清除”解决容器对象可能产生的循环引用的问题,并且通过“分代回收”以空间换取时间的方式来进一步提高垃圾回收的效率。
-
引用计数
#举例讲解概念 x = 10 # 直接引用 # y = x # 直接引用 变量名直接关联变量值 # z = x # 直接引用 变量名直接关联变量值 # x/y/z都分别绑定10的内存地址 print(id(x)) # 140708674410432 l = ['a', 'b', x] # 间接引用 print(id(l[2])) # 140708674410432 d = {'mmm': x} # 间接引用 print(id(d['mmm'])) # 140708674410432#举例讲解原理 x=10 l=['a','b',x] # 列表存储的实质是 l=['a'的内存地址,'b'的内存地址,10的内存地址] x=123 print(l[2]) # 10#举例讲解原理 x = 10 print(id(x)) # 140708995274688 print(id(10)) # 140708995274688 x = 12 print(id(x)) # 140708995274752 print(id(12)) # 140708995274752 -
标记清除
用来解决循环引用带来的内存泄露问题。
# 循环引用=>导致内存泄露 l1 = [111, ] l2 = [222, ] l1.append(l2) # l1=[值111的内存地址,l2列表的内存地址] l2.append(l1) # l2=[值222的内存地址,l1列表的内存地址] print(l1) # [111, [222, [...]]] print(l2) # [222, [111, [...]]] print(l1[1]) # [222, [111, [...]]] print(l2[1]) # [111, [222, [...]]] print(id(l1)) # 2619110589312 print(id(l2[1])) # 2619110589312 print(id(l2)) # 2619109535616 print(id(l1[1])) # 2619109535616根据上述代码,l1与l2对列表直接引用,但两列表间又相互间接引用,此时若执行如下代码:
del l1 del l2此时,l1与l2对列表的直接引用被解除,列表也不能被访问,但两列表的引用计数却不为0,这种状况下会被标记清除机制识别为垃圾而被清除。
#若只解除一个对应关系 del l1此时,仍能根据l2访问到原l1对应列表里的数据,故两列表均不会被垃圾回收机制清除。
判断是否能被访问到,是从栈区的变量名开始,顺着绑定关系线去堆区查找这条关系线对应的数据,若数据有间接引用线,也顺着去找被间接引用的数据,若数据可以被访问到则不会被认为成垃圾而清除。
直接引用与间接引用
直接引用指的是从栈区出发直接引用到的内存地址。
间接引用指的是从栈区出发引用到堆区后,再通过进一步引用才能到达的内存地址。
如:
l2 = [20, 30] # 列表本身被变量名l2直接引用,包含的元素被列表间接引用
x = 10 # 值10被变量名x直接引用
l1 = [x, l2] # 列表本身被变量名l1直接引用,包含的元素被列表间接引用
图解如下:
参考文章
-
分代回收
用来降低引用计数的扫描频率,提升垃圾回收的效率。
分代回收的核心思想是:在历经多次扫描的情况下,都没有被回收的变量,GC机制就会认为,该变量是常用变量,GC对其扫描的频率会降低。
二、交互语句
-
接收用户输入
python 3:input——且会将用户输入的所有内容都存成字符串类型
name = input("请输入您的用户名:") print(name, type(name))age = input("请输入的你的年龄: ") # 输入18 print(age, type(age)) # 18,str age=int(age) # int只能将纯数字(整数)的字符串转成整型 print(age > 16) #Truepython 2.7(了解):
raw_input——用法与python3的input一模一样 input——要求用户必须输入一个明确的数据类型,输入的是什么类型,就存成什么类型。
-
字符串格式化输出
%:值按照位置与%s一一对应,少一个不行,多一个也不行。
res = "my name is %s my age is %s" %('Python',"30") print(res) # my name is Python my age is 30 res = "my name is %s my age is %s" %("30",'Python') print(res) # my name is 30 my age is Python res = "my name is %s" %"Python" print(res) # my name is Python以字典的形式传值,打破位置对应的限制。
res = "我的名字是 %(name)s 我的年龄是 %(age)s" %{"age":"30","name":'Python'} print(res) # 我的名字是 Python 我的年龄是 30%s可以接收任意类型
print('my age is %s' %18) # my age is 18 print('my age is %s' % "Hello") # my age is Hello print('my age is %s' %[1,23]) # my age is [1, 23] print('my age is %s' %{'a':333}) # my age is {'a': 333}%d只能接收int
print('my age is %d' %18) # %d只能接收int # my age is 18 print('my age is %d' %"18") #报错str.format:兼容性好。
按位置传值:
res = '我的名字是 {} 我的年龄是 {}'.format('JL',19) print(res) # 我的名字是 JL 我的年龄是 19 res='我的名字是 {0}{0}{0} 我的年龄是 {1}{1}'.format('JL',19) print(res) # 我的名字是 JLJLJL 我的年龄是 1919打破位置的限制,按照key=value传值:
res="我的名字是 {name} 我的年龄是 {age}".format(age=19,name='JL') print(res) # 我的名字是 JL 我的年龄是 19f' ':3.5版本推出,低版本不支持。
x = input('your name: ') y = input('your age: ') res = f'我的名字是{x} 我的年龄是{y}' print(res)#了解f的新用法:{}内的字符串可以被当做表达式运行 res=f'{10+3}' print(res) # 13 f'{print("aaaa")}' # aaaa