Python 教程 / 切片

切片

切片是Python最强大的特性之一,让我们能够高效地访问和操作序列(如列表、元组、字符串)中的元素。

索引体系

Python的索引体系分为正向索引和负向索引两种:

┌─────────────────────────────────────────────────────────────────────┐
│                    Python 索引体系图解                               │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   列表:   ['P',    'y',    't',    'h',    'o',    'n']           │
│            [0]     [1]     [2]     [3]     [4]     [5]   ← 正向索引 │
│           [-6]    [-5]    [-4]    [-3]    [-2]    [-1]  ← 负向索引 │
│                                                                     │
│   正向索引从 0 开始,从左到右依次递增                                 │
│   负向索引从 -1 开始,从右到左依次递减                               │
│                                                                     │
│   ┌─────────────────────────────────────────────────────────────┐  │
│   │                                                             │  │
│   │   -6  -5  -4  -3  -2  -1                                    │  │
│   │    ↓   ↓   ↓   ↓   ↓   ↓                                    │  │
│   │   [P] [y] [t] [h] [o] [n]                                   │  │
│   │    ↓   ↓   ↓   ↓   ↓   ↓                                    │  │
│   │    0   1   2   3   4   5                                    │  │
│   │                                                             │  │
│   └─────────────────────────────────────────────────────────────┘  │
│                                                                     │
│   小技巧:                                                          │
│   • s[0] 永远指向第一个元素                                         │
│   • s[-1] 永远指向最后一个元素                                       │
│   • s[n] 和 s[n+len(s)] 在范围内时是等价的                         │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘ 
Python
s = ['P', 'y', 't', 'h', 'o', 'n']

print(s[0])     # 'P' - 第一个元素
print(s[5])     # 'n' - 第六个元素
print(s[-1])    # 'n' - 最后一个元素
print(s[-6])    # 'P' - 第一个元素
print(s[-6]) == s[0])  # True - 同一个元素 

基本切片语法

切片语法:s[start:end],返回从start到end-1的元素组成的子序列。

┌─────────────────────────────────────────────────────────────────────┐
│                      切片原理图解                                    │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   s = ['P', 'y', 't', 'h', 'o', 'n']                              │
│                                                                     │
│   s[1:4] 的切分过程:                                              │
│                                                                     │
│   ┌───┬───┬───┬───┬───┬───┐                                      │
│   │ P │ y │ t │ h │ o │ n │                                      │
│   └───┴───┴───┴───┴───┴───┘                                      │
│     0   1   2   3   4   5   ← 索引                               │
│         ↑           ↑                                              │
│        start        end (不包含!)                                  │
│                                                                     │
│   结果: ['y', 't', 'h']  ← 索引 1, 2, 3                           │
│                                                                     │
│   重要: end 位置的元素不包含在切片中!                               │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘ 
Python
s = ['P', 'y', 't', 'h', 'o', 'n']

# 基本切片 [start:end]
print(s[1:4])   # ['y', 't', 'h'] - 索引1,2,3
print(s[0:3])   # ['P', 'y', 't'] - 索引0,1,2
print(s[2:5])   # ['t', 'h', 'o'] - 索引2,3,4

# 省略 start(默认为0)
print(s[:3])    # ['P', 'y', 't'] - 等同于 s[0:3]

# 省略 end(默认为序列长度)
print(s[3:])    # ['h', 'o', 'n'] - 等同于 s[3:6]

# start 和 end 都省略
print(s[:])     # ['P', 'y', 't', 'h', 'o', 'n'] - 复制整个序列 

负索引切片

┌─────────────────────────────────────────────────────────────────────┐
│                    负索引切片图解                                  │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   s = ['P', 'y', 't', 'h', 'o', 'n']                              │
│                                                                     │
│        -6   -5   -4   -3   -2   -1                                │
│         ↓    ↓    ↓    ↓    ↓    ↓                                 │
│   ┌───┬───┬───┬───┬───┬───┐                                        │
│   │ P │ y │ t │ h │ o │ n │                                        │
│   └───┴───┴───┴───┴───┴───┘                                        │
│     0    1    2    3    4    5                                      │
│                                                                     │
│   s[-4:-1] = ['t', 'h', 'o']  ← 索引 -4, -3, -2                  │
│                                                                     │
│   s[0:-1] = ['P', 'y', 't', 'h', 'o']  ← 去掉最后一个             │
│                                                                     │
│   s[-3:] = ['h', 'o', 'n']  ← 最后三个元素                         │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘ 
Python
s = ['P', 'y', 't', 'h', 'o', 'n']

# 负索引切片
print(s[-4:-1])  # ['t', 'h', 'o'] - 索引 -4, -3, -2
print(s[-3:])     # ['h', 'o', 'n'] - 最后三个
print(s[:-2])     # ['P', 'y', 't', 'h'] - 去掉最后两个

# 混合使用正负索引
print(s[1:-1])    # ['y', 't', 'h', 'o'] - 去掉首尾
print(s[-5:3])    # ['y', 't'] - 索引 -5,-4,1,2 

步进切片

切片语法:s[start:end:step],step表示步长,默认为1。

┌─────────────────────────────────────────────────────────────────────┐
│                      步进切片图解                                    │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   s = ['P', 'y', 't', 'h', 'o', 'n']                              │
│        [0]  [1]  [2]  [3]  [4]  [5]                               │
│                                                                     │
│   s[::2]  步长为2,每隔一个取一个:                                  │
│                                                                     │
│   ┌───┬───┬───┬───┬───┬───┐                                        │
│   │ P │ y │ t │ h │ o │ n │                                        │
│   └───┴───┴───┴───┴───┴───┘                                        │
│     ↑       ↑       ↑                                               │
│    [0]    [2]    [4]   ← 索引 0, 2, 4                              │
│                                                                     │
│   结果: ['P', 't', 'o']                                            │
│                                                                     │
│   s[::-1]  步长为-1,反向取值:                                      │
│                                                                     │
│   ┌───┬───┬───┬───┬───┬───┐                                        │
│   │ P │ y │ t │ h │ o │ n │                                        │
│   └───┴───┴───┴───┴───┴───┘                                        │
│               ↑       ↑       ↑                                    │
│              [5]     [3]     [1]   ← 索引 5, 3, 1                  │
│                                                                     │
│   结果: ['n', 'h', 't', 'y', 'P']                                  │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘ 
Python
s = ['P', 'y', 't', 'h', 'o', 'n']

# 步进切片 [start:end:step]
print(s[::2])      # ['P', 't', 'o'] - 每隔一个
print(s[1::2])     # ['y', 'h', 'n'] - 从索引1开始,每隔一个
print(s[::3])     # ['P', 'h'] - 每隔三个

# 反转序列 (常用技巧!)
print(s[::-1])     # ['n', 'o', 'h', 't', 'y', 'P'] - 完全反转

# 负步长切片
print(s[5:2:-1])    # ['n', 'o', 'h'] - 从索引5到3,反向取
print(s[-1:-4:-1])   # ['n', 'o', 'h'] - 从最后一个到索引-4 
切片边界计算公式

对于正向切片 s[i:j:step]

  • 实际索引范围: i, i+step, i+2*step, ... 直到 j-1
  • 对于 step=1: i 到 j-1
  • 对于 step=-1: i 到 j+1(因为是递减)

切片赋值

切片不仅用于读取,还可用于赋值,实现批量修改元素。

┌─────────────────────────────────────────────────────────────────────┐
│                      切片赋值图解                                    │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  原列表: nums = [1, 2, 3, 4, 5]                                   │
│                                                                     │
│  ┌───┬───┬───┬───┬───┐                                            │
│  │ 1 │ 2 │ 3 │ 4 │ 5 │                                            │
│  └───┴───┴───┴───┴───┘                                            │
│        ↑─────↑                                                     │
│      [1:4]  ← 要替换的范围                                         │
│                                                                     │
│  nums[1:4] = [10, 20, 30] 后:                                       │
│                                                                     │
│  ┌───┬───┬───┬───┬───┬───┐                                        │
│  │ 1 │10 │20 │30 │ 5 │   │                                        │
│  └───┴───┴───┴───┴───┴───┘                                          │
│        ↑─────↑                                                     │
│     替换为 3 个元素,列表自动调整大小                                │
│                                                                     │
│  重要: 替换的元素个数可以和切片长度不同!                             │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘ 
Python
nums = [1, 2, 3, 4, 5]

# 替换部分元素 (长度相等)
nums[1:4] = [10, 20, 30]
print(nums)   # [1, 10, 20, 30, 5]

# 替换为更多元素 (列表变长)
nums = [1, 2, 3, 4, 5]
nums[1:3] = [10, 20, 30, 40]
print(nums)   # [1, 10, 20, 30, 40, 4, 5]

# 替换为更少元素 (列表变短)
nums = [1, 2, 3, 4, 5]
nums[1:4] = [100]
print(nums)   # [1, 100, 5]

# 删除元素 (赋值为空列表)
nums = [1, 2, 3, 4, 5]
nums[1:4] = []
print(nums)   # [1, 5]

# 插入元素 (空切片赋值)
nums = [1, 5]
nums[1:1] = [2, 3, 4]
print(nums)   # [1, 2, 3, 4, 5] 

切片复制 vs 引用

理解切片的复制行为非常重要:

┌─────────────────────────────────────────────────────────────────────┐
│                   切片复制 vs 引用图解                               │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  简单赋值 (共享引用):                                              │
│  ┌─────────────────────────────────────────────────────────────┐  │
│  │  original = [1, 2, 3]                                     │  │
│  │  copy_ref = original  # 不是复制,只是引用同一个对象!       │  │
│  │                                                             │  │
│  │  ┌─────────────┐                                           │  │
│  │  │ original ───┼───▶ [1, 2, 3]  ← 同一个对象              │  │
│  │  │ copy_ref ───┼───↗                                       │  │
│  │  └─────────────┘    ↗                                       │  │
│  │                                                             │  │
│  │  copy_ref.append(4)  # 同时影响 original!                    │  │
│  └─────────────────────────────────────────────────────────────┘  │
│                                                                     │
│  切片复制 (独立副本):                                              │
│  ┌─────────────────────────────────────────────────────────────┐  │
│  │  original = [1, 2, 3]                                     │  │
│  │  copy_list = original[:]  # 创建新的副本                   │  │
│  │                                                             │  │
│  │  ┌─────────────┐      ┌─────────────┐                     │  │
│  │  │ original ───┼───▶ [1, 2, 3]   │                        │  │
│  │  └─────────────┘      └─────────────┘                        │  │
│  │  ┌─────────────┐      ┌─────────────┐                       │  │
│  │  │ copy_list ───┼───▶ [1, 2, 3] ←── 独立的新对象!            │  │
│  │  └─────────────┘      └─────────────┘                       │  │
│  │                                                             │  │
│  │  copy_list.append(4)  # 不影响 original                      │  │
│  └─────────────────────────────────────────────────────────────┘  │
│                                                                     │
│  注意: 切片复制只做浅拷贝,如果列表嵌套可变对象,会有问题             │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘ 
Python
# 简单赋值 (共享引用)
original = [1, 2, 3]
copy_ref = original
copy_ref.append(4)
print(original)   # [1, 2, 3, 4] - original也变了!

# 切片复制 (独立副本)
original = [1, 2, 3]
copy_list = original[:]
copy_list.append(4)
print(original)   # [1, 2, 3] - original不变!
print(copy_list)   # [1, 2, 3, 4] 
浅拷贝问题

切片复制只做浅拷贝,即复制第一层元素。如果列表中嵌套了可变对象(如嵌套列表),内部对象仍然是共享引用:

original = [[1, 2], [3, 4]]
copy_list = original[:]
copy_list[0].append(5)  # 修改嵌套列表!
print(original)   # [[1, 2, 5], [3, 4]] - 内部列表被修改! 

实用技巧

Python
# 1. 复制整个列表
s = [1, 2, 3]
s_copy = s[:]

# 2. 前n个元素
s = ['a', 'b', 'c', 'd', 'e']
print(s[:3])    # ['a', 'b', 'c']

# 3. 后n个元素
print(s[-2:])    # ['d', 'e']

# 4. 判断回文 (常用!)
text = "上海自来水来自海上"
if text == text[::-1]:
    print("是回文")

# 5. 每n个元素取一个
s = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(s[::3])     # [1, 4, 7, 10] - 每3个取一个

# 6. 反转字符串/列表
text = "Python"
print(text[::-1])     # "nohtyP"

# 7. 去除首尾空格/元素
s = [0, 1, 2, 0]
print(s[1:-1])           # [1, 2] - 去掉首尾的0 

slice() 函数

Python内置slice()函数可以创建切片对象,便于重复使用。

Python
s = ['P', 'y', 't', 'h', 'o', 'n']

# 创建切片对象
my_slice = slice(1, 4)
print(s[my_slice])   # ['y', 't', 'h']

# 带步长的切片对象
step_slice = slice(0, 6, 2)
print(s[step_slice])  # ['P', 't', 'o']

# 只传两个参数
prefix_slice = slice(None, 3)  # 等同于 [:3]
print(s[prefix_slice])  # ['P', 'y', 't']

# 实用场景: 处理数据列
data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
col_slice = slice(1, 3)  # 取第2、3列
for row in data:
    print(row[col_slice])  # [2, 3], [5, 6], [8, 9] 

元组切片

切片同样适用于元组。元组切片返回新的元组。

Python
t = ('P', 'y', 't', 'h', 'o', 'n')

# 元组切片 (返回新元组)
print(t[1:4])    # ('y', 't', 'h')
print(t[::2])      # ('P', 't', 'o')
print(t[::-1])     # ('n', 'o', 'h', 't', 'y', 'P') 

章节测验

问题1: s = [0,1,2,3,4,5],s[1:4]的结果是?

问题2: s[::-1]是什么意思?

问题3: nums[1:3] = [10, 20]会替换多少个元素?

问题4: 切片副本和原始列表的关系是?

练习题

练习1: 去除首尾空格

使用切片去除字符串首尾的空格。

s = "   hello   "
# 去除首尾空格 
练习2: 分块处理

将列表每3个元素分成一组。

s = [1, 2, 3, 4, 5, 6, 7]
# 每3个一组: [[1,2,3], [4,5,6], [7]] 
练习3: 奇偶分离

使用切片将列表的奇数位和偶数位分开。

s = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 偶数位: [0, 2, 4, 6, 8]
# 奇数位: [1, 3, 5, 7, 9] 
🐍 Python 在线代码编辑器
📝 运行结果