【Day02 Java转Python】Python的ArrayList: list与tuple的“双面人生

容器类型(一):列表与元组

如果你是从Java转向Python的开发者,看到listtuple,第一反应很可能是:"这不就是ArrayList和不可变数组吗?" 没错,这个直觉非常准。但Python的列表和元组比Java的对应物更灵活、语法更简洁,甚至能让你写出"一行顶十行"的代码。

本文将带你深入理解Python中的这对"双面兄弟"------可变与不可变、动态与静态、丰富操作与严格约束,并通过与Java的对比,让你快速掌握它们的用法和适用场景。


一、list:Python 的"超级 ArrayList"

Java中的ArrayList是使用最广泛的动态数组,而Python的list就是它的"增强版"------不仅支持所有ArrayList的操作,还提供了切片、列表推导等杀手级特性。

1.1 创建与基本操作

python 复制代码
# 创建列表
fruits = ["apple", "banana", "cherry"]
numbers = [1, 2, 3, 4, 5]
mixed = [1, "hello", 3.14, True]   # Python列表可混合类型

# 增
fruits.append("orange")          # 末尾追加
fruits.insert(1, "grape")        # 指定位置插入
fruits.extend(["melon", "kiwi"]) # 合并另一个列表

# 删
fruits.remove("banana")          # 删除指定值(只删第一个)
popped = fruits.pop()            # 弹出末尾元素
del fruits[0]                    # 删除索引位置元素
fruits.clear()                   # 清空列表

# 改
fruits[0] = "blueberry"          # 直接赋值修改

# 查
print(fruits[2])                 # 索引访问
print(fruits[-1])                # 倒数第一个
print(fruits.index("cherry"))    # 查找索引
print("apple" in fruits)         # 成员判断

与Java对比:

操作 Java ArrayList Python list
追加 add(e) append(e)
插入 add(i, e) insert(i, e)
删除值 remove(o) remove(o)
删除索引 remove(i) pop(i)del lst[i]
长度 size() len(lst)
判空 isEmpty() not lstlen(lst)==0

Python胜在语法统一len()适用于所有容器,in操作符简洁直观。

1.2 切片:list 的"手术刀"

切片是Python最强大的特性之一,一次操作就能完成子数组的提取、复制、甚至原地替换。Java中需要循环或subList,而Python一行搞定。

python 复制代码
nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# 获取子列表 [2, 3, 4]
sub = nums[2:5]          # 起始索引:结束索引(不包含结束)

# 从开头到索引5(不含)
head = nums[:5]          # [0,1,2,3,4]

# 从索引5到末尾
tail = nums[5:]          # [5,6,7,8,9]

# 步长(每2个取1个)
every_second = nums[::2] # [0,2,4,6,8]

# 反转列表
reversed_nums = nums[::-1]  # [9,8,7,...,0]

# 复制列表(浅拷贝)
copy = nums[:]           # 等价于 nums.copy()

高级玩法:切片赋值

python 复制代码
nums = [0, 1, 2, 3, 4]
nums[1:3] = [10, 20, 30]   # 替换索引1~2为三个元素
print(nums)                # [0, 10, 20, 30, 3, 4]

nums[2:4] = []             # 删除索引2~3的元素
print(nums)                # [0, 10, 4]

这种原地修改的能力是Java ArrayList难以企及的。

1.3 列表推导式:声明式编程的典范

列表推导式(list comprehension)是Python独有的语法糖,它将循环和条件判断压缩进一个表达式,生成新列表。对于Java开发者来说,它相当于Stream API的简化版。

基础语法[表达式 for 变量 in 可迭代对象 if 条件]

python 复制代码
# 生成平方数列表
squares = [x**2 for x in range(10)]
# Java: IntStream.range(0,10).map(x -> x*x).boxed().collect(Collectors.toList())

# 带条件的过滤
even_squares = [x**2 for x in range(10) if x % 2 == 0]

# 嵌套循环(生成坐标对)
coords = [(x, y) for x in range(3) for y in range(3)]
# [(0,0),(0,1),(0,2),(1,0),...]

# 条件表达式(三元)
results = [x if x > 0 else 0 for x in [-1, 2, -3, 4]]

与Java的Stream对比:

功能 Java Stream Python列表推导
map .map(f) [f(x) for x in list]
filter .filter(p) [x for x in list if p(x)]
flatMap .flatMap(f) [y for x in list for y in f(x)]

列表推导式更紧凑、更易读(对Python程序员而言)。而且由于是立即执行,不需要终端操作。

1.4 其他常用方法

python 复制代码
nums = [3, 1, 4, 1, 5, 9, 2]
nums.sort()              # 原地排序
sorted_nums = sorted(nums)  # 返回新列表,原列表不变
nums.reverse()           # 原地反转
print(sum(nums))         # 求和
print(max(nums), min(nums))
print(nums.count(1))     # 统计出现次数

二、tuple:不可变的"定海神针"

元组(tuple)与列表几乎一模一样,除了一个关键区别:不可变。一旦创建,不能增、删、改。这让它天然具备哈希能力,可以作为字典的键,也是函数多返回值的不二之选。

2.1 创建与访问

python 复制代码
# 创建元组
point = (10, 20)
single = (5,)            # 只有一个元素时必须有逗号
empty = ()

# 访问(与列表相同)
print(point[0])          # 10
print(point[-1])         # 20

# 不可变性演示
point[0] = 30            # TypeError: 'tuple' object does not support item assignment

2.2 元组的不可变 ≠ 内容不可变

注意:如果元组内包含可变对象(如列表),该对象本身可以改变。元组只是"引用"不可变。

python 复制代码
t = (1, 2, [3, 4])
t[2].append(5)           # 合法!列表内容改变了
print(t)                 # (1, 2, [3, 4, 5])
# t[2] = [6,7]           # 错误!不能更换引用

这一点和Java中final修饰的引用类型变量类似。

2.3 元组的常用操作

由于不可变,元组的方法很少:count(计数)、index(查找索引)。但许多列表的操作(如lenin、切片)同样适用于元组。

python 复制代码
t = (1, 2, 3, 2, 2)
print(t.count(2))        # 3
print(t.index(3))        # 2
print(t[1:3])            # (2, 3) 切片返回新元组

2.4 元组的解包(Unpacking)------ Python的优雅之处

元组最实用的功能之一是解包,尤其适合函数返回多个值。

python 复制代码
# 简单解包
a, b = (10, 20)

# 交换变量(无需临时变量)
x, y = y, x

# 函数返回多个值
def get_user():
    return "Alice", 25

name, age = get_user()
print(name, age)

# 带星号收集剩余元素
first, *rest = (1, 2, 3, 4)   # first=1, rest=[2,3,4]

Java中返回多值通常需要自定义类或Pair/Tuple库,而Python原生支持。

2.5 元组作为字典的键

由于元组是不可变的,它可以作为字典的键,而列表不行。

python 复制代码
locations = {}
locations[(35.68, 139.76)] = "Tokyo"   # 经纬度元组作为键
# locations[[1,2]] = "error"           # 报错:unhashable type: 'list'

三、list vs tuple:如何选择?

场景 推荐 原因
元素数量会变化 list 可变,增删改方便
需要作为字典的键 tuple 不可变,可哈希
函数返回多个值 tuple 轻量、解包方便
存储同质数据(如所有整数) list 通常需要修改或扩展
配置常量(如颜色RGB值) tuple 语义上不应改变
性能要求高且数据固定 tuple 创建速度略快,内存占用更小

性能小贴士:在相同数据量下,元组的创建速度比列表快约10~30%,内存占用也更少。但如果数据频繁修改,列表更合适。


四、与Java的思维转换总结

概念 Java Python
动态数组 ArrayList<E> list(混合类型)
不可变列表 List.of(...) 返回不可变List tuple
子数组/切片 list.subList(from, to) lst[start:end]
复制列表 new ArrayList<>(list) lst[:]lst.copy()
列表推导 Stream API + collector [expr for x in list]
多返回值 自定义类或Object[] (a, b) 元组+解包
交换变量 临时变量 a, b = b, a

Python的哲学:简洁优于复杂,直接优于间接。当你熟练使用切片和列表推导后,会发现很多原本需要循环的代码都可以被一行取代。


五、动手练习:巩固你的理解

尝试用Python实现以下任务,并思考如果用Java会怎么写:

  1. 给定一个列表nums = [1,2,3,4,5,6],取出所有奇数,并计算它们的平方,生成新列表。
  2. 交换列表中的第一个和最后一个元素。
  3. 将两个列表keys = ["name", "age"]values = ["Alice", 25]合并成一个字典。
  4. 编写一个函数,接受任意多个参数,返回它们的和与平均值(用元组返回)。

参考解答

python 复制代码
# 1
nums = [1,2,3,4,5,6]
result = [x**2 for x in nums if x % 2 == 1]   # [1, 9, 25]

# 2
nums[0], nums[-1] = nums[-1], nums[0]

# 3
d = dict(zip(keys, values))   # {'name': 'Alice', 'age': 25}

# 4
def stats(*args):
    total = sum(args)
    avg = total / len(args)
    return total, avg

Python的listtuple虽然简单,却是日常编程中使用频率最高的数据结构。理解它们的特性,尤其是切片和推导式,能让你写出更Pythonic的代码。下一篇文章我们将继续探讨Python的其他容器类型:dictset,敬请期待!

当你开始习惯用一行列表推导代替四五行循环,用元组解包优雅地交换变量,你会感受到Python设计的精妙------让程序员专注于业务逻辑,而非繁琐的语法。

相关推荐
回到原点的码农8 小时前
Spring Boot 3.3.4 升级导致 Logback 之前回滚策略配置不兼容问题解决
java·spring boot·logback
暴力袋鼠哥8 小时前
基于 LightGBM 的山东高考智能择校推荐系统设计与实现
python·django·flask
jwt7939279378 小时前
SpringBoot实现异步调用的方法
java·spring boot·spring
jiankeljx9 小时前
Spring Boot文件上传
java·spring boot·后端
计算机安禾9 小时前
【数据结构与算法】第25篇:静态查找(一):顺序查找与折半查找
java·开发语言·数据结构·学习·算法·visual studio code·visual studio
cch89189 小时前
易语言与Java对比:中文编程VS跨平台王者
java·开发语言
minji...9 小时前
Linux 多线程(一)线程概念,轻量级进程,执行流,线程创建
java·开发语言·jvm
5系暗夜孤魂9 小时前
当系统不再“透明”:从 Java 技术体系看大型工程的可观测性与可掌控性
java·python·压力测试
0xDevNull9 小时前
Java 17 新特性概览与实战教程
java·开发语言·后端