【python】进阶之基础回顾(一)

1 基础回顾

1.1变量赋值和引用

  • 当有一个新变量的时候,内存空间就会开辟一块数据存储
  • 变量不同,地址是不同的,可以用id( )获取内存地址

变量引用的本质就是将这个变量的内存地址,关联到一个新变量中,两个变量指向的是同一个地址,

所以变量是不占内存的,

1.2 小整数池

小整数池就是Python解释器在程序开始运行的时候就预先开辟的一块内存空间,存放一部分的整数,方便后面去调用,用于优化资源消耗的

1.3 垃圾回收机制

变量使用前需要先定义,定义就是开辟了空间,如果需要用到很多数据那么就会开辟很多空间,空间是有限的,开多了会造成浪费和溢出的风险,所以需要在使用后就释放这个空间,

python解释器自动的帮我们做了这个清理内存空间的机制,

采用的是引用计数的方式回收垃圾。

什么是垃圾?垃圾就是没有绑定变量名的值,也就是无法访问的值,就是没有用的值

如何回收垃圾?:通过引用计数的方式,就是当这个值被引用的时候,就会绑定到一个新的变量名上,引用计数就会加1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
x = 10	# x绑定给值10,10的引用计数=1
y = x # y绑定给值10,10的引用计数=2
z = 10 # z绑定给值10,10的引用计数=3

# 通过赋值可以将变量名绑定到值,将引用计数增加
# 通过del 方法可以将变量名和值解绑,将引用计数减少

del z # z与它所绑定的值解绑,即值10的引用计数减为2
# 注意 del不是不是删除z的意思本质是接触变量名的绑定,内存回收的目的

import sys
sys.getrefcount(a) # 查看引用计数

def f():
import sys
a = 10
print(sys.getrefcount(a))
b = a
print(sys.getrefcount(a))
c = [a]
print(sys.getrefcount(a))
del b
print(sys.getrefcount(a))
del c
print(sys.getrefcount(a))

拓展:py的垃圾回收机制,除了引用计数之外,还有【标记回收】、【分代回收】

1
2
3
4
5
6
7
8
9
# 标记清除解决循环引用造成的问题
l1=[]
l2=[]
l1.append(l2)
l2.append(l1)

del l1, l2

# 分代回收解决引用计数效率低的问题

1.4 迭代器

【可迭代对象(iterable)衣特伯】是啥?

指的是可以依次返回其内部成员的对象,比如字符串、列表、字典、文件等等都是可迭代的对象

【迭代器(iterator)衣特瑞儿】是啥?

内置函数__iter(可迭代对象)得到迭代器,本质上迭代器也是可迭代对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 可迭代对象,从语法上说就是那些具有__iter__的方法的对象
# 迭代器,从语法上说就是那些同事具有__next__和__iter__方法的对象。
- 迭代器调用__next__方法会调用迭代器中的下一个值;
- 迭代器调用__iter__方法返回迭代器本身;
# 示例:
>>> s={1,2,3} # 可迭代对象s
>>> i=iter(s) # i是迭代器
>>> next(i) # 返回迭代器中下一个值
1
>>> next(i)
2
>>> next(i)
3
>>> next(i) #抛出StopIteration的异常,代表无值可取,迭代结束

优点:惰性取值;每次只取一个数据,不占内存

缺点:只能从前往后依次取值,不能返回头往前取值。就像象棋中的卒。只进不退

1.5 for 循环的本质

while循环可以做循环遍历操作,但是远不如for 循环简洁实用。

while循环适合做条件循环,for 循环适合做迭代器循环

【for循环的本质】:for循环底层利用了迭代器的原理

1
2
3
4
5
6
7
8
9
10
11
# while + iterator
goods = ['mac','len','huawei','xiaomi']
goods_iterator = iter(goods)
while ture:
tyr:
print(next(goods_iterator)) # 无限循环依次取值
except StopIteration: # 无限循环什么时候终止?捕捉异常终止循环
break

for i in goods:
print(i)

for 循环底层实现分三步

第一:调用iter(),将goods转化成迭代器goods_iterator

第二: 调用next() 方法到迭代器goods_iterator取值

第三:循环调用第二步,直到捕捉到异常后终止循环

【for循环的好处】:为序列和非序列类型提供了一种统一的迭代取值的方式

1.6 chain

python官方提供了itertools工具包,方便操作迭代器,这个包里提供了chian函数,兼顾内存效率和写法优雅

1
2
3
4
5
6
7
8
from itertools import chian
a= [1,2,3,4,5]
b = [4,5,65,56]
c = {'a':1,'b':4}
for i in chain(a,b):
print(i) # 1, 2 ,3 ,4,5,4,5,65,56
for i in chain(a,c.values()):
print(i) # 1,2,3,4,5,1,4

去除嵌套

1
2
3
4
5
6
7
from itertools import chain
a = [[1,2,3],[4,5,6],[7,8,9]]
for i in chain(a):
print(i) # 1,2,3,4,5,6,7,8,9
# 取值
b = list(chian(*a)) # [1,2,3,4,5,6,7,8,9]

练习:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 解嵌套、
a = [[1,2,3],[8,2,5],[1,5,9]]
test1 = [m for i in a for m in i] # [1, 2, 3, 3, 4, 5, 5, 6, 7]
test2 = list (itertools.chian(*a)) # [1, 2, 3, 3, 4, 5, 5, 6, 7]
test3 = sum(a,start=[]) # [1, 2, 3, 3, 4, 5, 5, 6, 7]
# 解嵌套、去重
test1 = list(setm for i in a for m in i()) # [1, 2, 3, 5, 8, 9]
test2 = list(set(itertools.chian(*a))) # [1, 2, 3, 5, 8, 9]
test3 = list(set(sum(a,start=[]))) # [1, 2, 3, 5, 8, 9]
# 解嵌套、去重、不破坏排序
# 方式一
new_list = []
test_set = set()
for i in a:
m_list=[]
for m in i:
if m not in test_set:
m_list.append(m)啊
test_set.add(m)
new_list.append(m_list)
# print(new_list)
test1 = [m for i in new_list for m in i]
print(test1) # [1, 2, 3, 8, 5, 9]
# 方式二:
test2 = list(dict.fromkeys(itertools.chain(*a)))
print(test2) # [1, 2, 3, 8, 5, 9]

【python】进阶之基础回顾(一)
http://example.com/2024/03/18/601python进阶之基础回顾(一)/
作者
Wangxiaowang
发布于
2024年3月18日
许可协议