当前位置:首页>python>第 04 篇|Python 列表深度解析:比 JS 数组还好用的数据结构

第 04 篇|Python 列表深度解析:比 JS 数组还好用的数据结构

  • 2026-09-08 04:44:33
第 04 篇|Python 列表深度解析:比 JS 数组还好用的数据结构

前言

上一篇讲语法对比的时候,列表和数组的基本操作一笔带过了。

这篇我们深入聊聊 Python 列表——尤其是两个前端不常见但非常强大的特性:切片操作 和 列表推导式。

学完这两个,你会理解为什么很多人说"Python 的列表比 JS 数组好用"。


一、列表的增删改查(对比 JS 数组)

先把基本操作过一遍,熟悉的直接跳过。

# 创建列表
fruits = ["苹果", "香蕉", "橙子", "葡萄"]

# 访问元素(索引从 0 开始)
print(fruits[0])    # 苹果
print(fruits[-1])   # 葡萄(负数索引!从末尾倒数)
print(fruits[-2])   # 橙子

# 修改元素
fruits[1] = "芒果"
print(fruits)       # ['苹果', '芒果', '橙子', '葡萄']

# 添加元素
fruits.append("草莓")       # 末尾添加(类比 push)
fruits.insert(1, "西瓜")    # 指定位置插入

# 删除元素
fruits.remove("芒果")       # 按值删除
fruits.pop()                 # 删除末尾(类比 pop)
fruits.pop(0)                # 删除指定索引

# 查询
print(len(fruits))           # 长度(注意:len() 是函数)
print("苹果" in fruits)      # True/False,比 includes() 更自然
print(fruits.index("橙子"))  # 返回索引

负数索引是 Python 特有的,JS 没有这个:

arr = [10, 20, 30, 40, 50]
print(arr[-1])   # 50,最后一个
print(arr[-2])   # 40,倒数第二个

二、切片操作:Python 最优雅的特性之一

切片(Slice)是 Python 列表的独有功能,JS 里的 slice() 方法只是它的简化版。

基本语法:list[start:end:step]

nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# 基本切片 [start:end](不包含 end)
print(nums[2:5])    # [2, 3, 4]

# 省略 start(从头开始)
print(nums[:4])     # [0, 1, 2, 3]

# 省略 end(到末尾)
print(nums[6:])     # [6, 7, 8, 9]

# 负数切片
print(nums[-3:])    # [7, 8, 9],最后三个
print(nums[:-2])    # [0, 1, 2, 3, 4, 5, 6, 7],去掉最后两个

# 带步长 [start:end:step]
print(nums[::2])    # [0, 2, 4, 6, 8],每隔一个取一个
print(nums[1::2])   # [1, 3, 5, 7, 9],奇数索引
print(nums[::-1])   # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0],反转列表!

最后那个 [::-1] 是经典用法:一行代码反转列表。 JS 里要用 .reverse()(而且会修改原数组),Python 的切片不修改原列表,返回新列表。

对比 JS 的 slice():

// JS
const nums = [0, 1, 2, 3, 4, 5];
nums.slice(2, 5);   // [2, 3, 4]
nums.slice(-3);     // [3, 4, 5]
// JS 没有步长参数
# Python
nums = [0, 1, 2, 3, 4, 5]
nums[2:5]           # [2, 3, 4]
nums[-3:]           # [3, 4, 5]
nums[::2]           # [0, 2, 4],JS 做不到

三、列表推导式:优雅到令人上瘾

列表推导式(List Comprehension)是 Python 最受欢迎的特性之一,用一行代码代替 map 和 filter。

基本格式:[表达式 for 变量 in 可迭代对象]

从 JS 的 map 迁移:

// JS map
const nums = [1, 2, 3, 4, 5];
const doubled = nums.map(n => n * 2);
// [2, 4, 6, 8, 10]
# Python 列表推导式
nums = [1, 2, 3, 4, 5]
doubled = [n * 2 for n in nums]
# [2, 4, 6, 8, 10]

从 JS 的 filter 迁移:

// JS filter
const evens = nums.filter(n => n % 2 === 0);
// [2, 4]
# Python 列表推导式(带条件)
evens = [n for n in nums if n % 2 == 0]
# [2, 4]

map + filter 组合:

// JS:先过滤偶数,再乘以 2
const result = nums.filter(n => n % 2 === 0).map(n => n * 2);
// [4, 8]
# Python:一行搞定
result = [n * 2 for n in nums if n % 2 == 0]
# [4, 8]

更多实用例子:

# 生成平方数列表
squares = [x**2 for x in range(1, 6)]
# [1, 4, 9, 16, 25]

# 字符串列表转大写
words = ["hello", "world", "python"]
upper = [w.upper() for w in words]
# ['HELLO', 'WORLD', 'PYTHON']

# 处理字典列表(JSON 数据很常见)
users = [
    {"name": "Alice", "age": 25},
    {"name": "Bob", "age": 17},
    {"name": "Charlie", "age": 30}
]
# 取出所有成年用户的名字
adult_names = [u["name"] for u in users if u["age"] >= 18]
# ['Alice', 'Charlie']

最后那个例子在处理接口返回的 JSON 数据时非常实用!


四、浅拷贝 vs 深拷贝:和 JS 一样的坑

这个坑 JS 也有,Python 也有,面试也常考。

# 直接赋值:两个变量指向同一个列表
a = [1, 2, 3]
b = a
b.append(4)
print(a)  # [1, 2, 3, 4],a 也被修改了!

# 浅拷贝:复制一层
a = [1, 2, [3, 4]]
b = a.copy()      # 或者 b = a[:]
b[0] = 99
print(a)  # [1, 2, [3, 4]],第一层没被改

b[2].append(5)   # 修改嵌套列表
print(a)  # [1, 2, [3, 4, 5]],嵌套层被改了!

浅拷贝只复制第一层,嵌套的对象还是共享引用。

# 深拷贝:完全独立的副本
import copy

a = [1, 2, [3, 4]]
b = copy.deepcopy(a)
b[2].append(5)
print(a)  # [1, 2, [3, 4]],完全不受影响

对比 JS 的做法:

// JS 浅拷贝
const a = [1, 2, [3, 4]];
const b = [...a];           // 或 a.slice()

// JS 深拷贝(常用方法)
const c = JSON.parse(JSON.stringify(a));  // 简单数据可用
const d = structuredClone(a);             // 现代浏览器推荐

规律: 数据结构只有一层,用 .copy() 或 [:];有嵌套结构,用 copy.deepcopy()。


小结

  1. 负数索引 arr[-1] 是 Python 特有的,获取末尾元素很方便
  2. 切片 arr[start:end:step] 功能强大,[::-1] 一行反转列表
  3. 列表推导式 [x for x in arr if 条件] 是 map + filter 的优雅替代
  4. 拷贝陷阱:直接赋值是引用,一层用 .copy(),有嵌套用 copy.deepcopy()

下篇预告: 第 05 篇,Python 字典深度解析。字典就是 Python 的对象/JSON,前端最有亲切感——但里面也有很多 JS 没有的好用功能等你来发现。


最新文章

随机文章