当数组遇上Python,事情变得有趣了
Python数组?不就是用方括号包起来的东西嘛?等等!先别急着划走!(信我!)你以为的数组可能只是冰山一角。见过能自动变长的数组吗?体验过数组原地倒序的神操作吗?知道怎么用数组玩转矩阵运算吗?今天我们就来扒一扒Python数组的那些骚操作!
基础操作里的魔鬼细节
# 经典创建方式
my_list = [1,2,3] # 注意是方括号!
# 你以为的追加操作
my_list.append(4) # → [1,2,3,4]
# 但Python允许这样玩(惊不惊喜?)
my_list += [5,6] # 等效于extend方法 → [1,2,3,4,5,6]
这里有个坑(划重点):append()
和extend()
完全是两码事!试过把my_list.append([7,8])
吗?结果会变成[1,2,3,4,5,6,[7,8]]
,这可不是你想要的吧?
切片操作的黑科技
Python数组的切片简直不要太强!试试这些操作:
arr = [0,1,2,3,4,5]
# 基础切片
print(arr[1:4]) # [1,2,3]
# 步长设置
print(arr[::2]) # 隔一个取一个 → [0,2,4]
# 倒序神器
print(arr[::-1]) # 原地倒序 → [5,4,3,2,1,0]
# 替换魔法
arr[2:4] = [99,100] # → [0,1,99,100,4,5]
(重要!)切片操作实际上创建了新列表,想修改原数组记得用arr[:] = ...
这种写法!
动态数组的隐藏属性
Python列表本质上是动态数组,这意味着:
- 自动扩容:当元素超过当前容量时,自动申请1.125倍的新空间(实测数据)
- 内存预分配:提前预留空间减少频繁内存操作
- 异构存储:可以同时存数字、字符串甚至其他列表!
来看个性能对比:
# 低效写法
new_list = []
for i in range(1000000):
new_list.append(i)
# 高效写法(速度提升5倍+)
new_list = [0] * 1000000 # 预分配空间
for i in range(1000000):
new_list[i] = i
高级玩法合集
- 列表推导式(装逼必备):
# 生成二维数组
matrix = [[i*j for j in range(5)] for i in range(5)]
- 数组拆包(Python3.5+):
first, *middle, last = [1,2,3,4,5]
# first=1, middle=[2,3,4], last=5
- 内存视图(处理大型数据):
import array
data = array.array('d', [1.0]*1000000)
view = memoryview(data) # 零拷贝操作
- 数组与生成器(内存优化):
# 生成器表达式
big_data = (x**2 for x in range(1000000)) # 不立即占用内存
性能陷阱预警!
虽然Python数组很强大,但有些操作要特别小心:
- 在头部插入元素(insert(0, item))→ O(n)时间复杂度
- 频繁拼接小数组 → 用
itertools.chain
代替 - 超大数组查找 → 考虑转set或使用bisect模块
实测案例:包含100万元素的列表,x in list
需要1.5毫秒,而x in set
只需要0.03微秒!
数组的七十二变
你以为数组只能存数据?Too young!
- 当栈用:append()+pop()
- 当队列用:collections.deque
- 当矩阵用:numpy.array
- 当数据库用:配合pickle模块持久化存储
- 甚至可以实现图结构!(邻接表表示法)
# 用列表实现树结构
class TreeNode:
def __init__(self, val):
self.val = val
self.children = [] # 数组存储子节点
root = TreeNode(1)
root.children.append(TreeNode(2))
root.children.append(TreeNode(3))
你以为结束了?这才刚开始!
Python数组就像瑞士军刀,用得好能玩出各种花样。但记住:不要为了炫技而炫技!实际开发中要根据需求选择最合适的数据结构。比如需要频繁查找就用字典,需要高效排序就用堆…(不过这些又是另一个故事了)
最后灵魂一问:你还在用for i in range(len(list))
吗?试试enumerate()
吧,真香!下次见~