Python3中zip()函数使用详解:内存机制与多维应用
本文深入解析Python3中zip()函数的核心机制,重点说明其作为迭代器仅能访问一次的内存优化特性,对比Python2的差异。详细演示单参数、多参数及矩阵场景下的用法,包括列表推导式实现矩阵加减点乘,以及利用*zip进行数据解包还原的方法,帮助开发者避免常见错误并高效处理多维数据。
在Python3中,出于内存优化的考虑,zip()函数生成的对象只能被访问一次。这与Python2的行为不同,在Python2中zip返回的是列表,可以多次访问。开发者在使用时必须注意这一关键区别,避免因重复迭代导致数据丢失。
* coding: utf-8 *
zip()函数的基本定义是从多个传入的迭代器中依次取出元素,组合成一个新的迭代器。其返回值是一个zip对象,内部元素为元组。该对象可以转换为列表或元组以方便查看或使用。传入的参数可以是元组、列表、字典等任何支持迭代的对象。当zip()函数仅接收一个参数时,即zip(iterable),它会从该迭代器中依次取出元素,并将每个元素包装成一个单元素元组,最终组成一个新的迭代器。
在Python 3.0及以上版本中存在一个重要的行为特征:zip对象中的数据只能操作一次。一旦迭代完成,其内部内存资源会被释放。如果试图在下一次访问该zip对象,将会引发错误或返回空结果,例如在示例1中尝试再次输出zip对象时就会遇到这种情况。
具体表现为访问已耗尽的zip对象时会报错或返回空列表,如例子1中的输出操作所示,这验证了上述内存释放机制。
1、zip()函数单个参数的应用情况
print(‘=‘*10 + “zip()函数单个参数” + ‘=‘*10) list1 = [1, 2, 3, 4] tuple1 = zip(list1) list2=list(tuple1)
首先打印zip函数的返回类型以确认其数据结构。
代码示例:print(“zip()函数的返回类型:\n”, type(tuple1)),执行结果显示其类型为zip。
接下来演示如何将zip对象转化为列表以便查看具体内容。
print(“zip对象转化为列表:\n”, list(tuple1))#值为[(1,), (2,), (3,), (4,)] print(“zip对象转化为列表:\n”, list(tuple1))#值为[] print(“list2输出的列表1为:\n”,list2) print(“list2输出的列表2为:\n”,list2)
当zip()函数接收两个参数时,即zip(a,b),函数会分别从迭代器a和b中依次各取出一个元素,组成一个元组。随后,将这些依次组成的元组合并成一个新的迭代器,即新的zip类型数据。需要注意的是,虽然zip不强制要求a与b的维数完全相同,但当两者具有相同的行数与列数时,会正常组合对应位置的元素。若a与b的行数或列数不同,zip会取两者结构中最小的行数和列数,依据这个最小维度将对应位置的元素进行组合。这种行为在效果上类似于调用itertools.zip_longest(*iterables)函数,但zip_longest会填充缺失值,而zip直接截断。
2、zip()函数有两个参数的具体场景
print(‘=‘*10 + “zip()函数有2个参数” + ‘=‘*10) m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] n = [[2, 2, 2], [3, 3, 3], [4, 4, 4]] p = [[2, 2, 2], [3, 3, 3]]
测试行与列相同的情况
代码示例:print(“行与列相同:\n”, list(zip(m, n)))
执行结果为:[([1, 2, 3], [2, 2, 2]), ([4, 5, 6], [3, 3, 3]), ([7, 8, 9], [4, 4, 4])]。
测试行与列不同的情况
代码示例:print(“行与列不同:\n”, list(zip(m, p)))
执行结果为:[([1, 2, 3], [2, 2, 2]), ([4, 5, 6], [3, 3, 3])]。可以看到,由于p矩阵较短,结果被截断,只保留了前两组对应元素。
3、zip()的实际应用,也可以结合for循环与列表推导式来实现更复杂的逻辑。
利用zip进行矩阵相加减及点乘运算
定义两个3x3矩阵:m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]],n = [[2, 2, 2], [3, 3, 3], [4, 4, 4]]。
演示矩阵点乘操作
print(‘=‘*10 + “矩阵点乘” + ‘='10)#左右两端各有10个 print([x*y for a, b in zip(m, n) for x, y in zip(a, b)]) [2, 4, 6, 12, 15, 18, 28, 32, 36]
矩阵相加与相减的逻辑与点乘类似,只需改变运算符即可。
print(‘=‘*10 + “矩阵相加,相减” + ‘=‘*10) print([x+y for a, b in zip(m, n) for x, y in zip(a, b)]) [3, 4, 5, 7, 8, 9, 11, 12, 13]
4、*zip的操作限制
m5=[1,2,3] n5=[4,5,6] k5=[7,8,9] zip5=zip(m5,n5,k5) print(“list(zip5):”,list(zip5))不能输出,否则zip(*zip5)
如果对已经耗尽的zip对象直接执行*zip操作,将无法执行或得到预期外的结果,如前文所述,必须先保存或使用一次。
m6,n6,k6=zip(*zip5) print(“m6:”,m6)#m6: (1, 2, 3) print(“n6:”,n6)#n6: (4, 5, 6) print(“k6:”,k6)#k6: (7, 8, 9)
5、*zip()函数的用法
*zip()函数是zip()函数的逆过程,用于将zip对象还原为原先组合前的数据。通过解包操作,可以将打包后的元组序列重新分离为原始的多个迭代器。
print(‘=‘*10 + “*zip()函数” + ‘=‘*10) m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] n = [[2, 2, 2], [3, 3, 3], [4, 4, 4]] print(“zip(m, n)返回:\n”, zip(m, n)) # print(“*zip(m, n)返回:\n”, *zip(m, n)) *zip(m, n)返回:([1, 2, 3], [2, 2, 2]) ([4, 5, 6],[3, 3, 3]) ([7, 8, 9], [4, 4, 4]) print(“list(zip(m, n))返回:\n”, list(zip(m, n))) list(zip(m, n))返回: [([1, 2, 3], [2, 2, 2]), ([4, 5, 6], [3, 3, 3]), ([7, 8, 9], [4, 4, 4])] m2, n2 = zip(*zip(m, n))#先合到一块 print(“m2:”,m2)#([1, 2, 3], [4, 5, 6], [7, 8, 9]) print(“n2:”,n2)#([2, 2, 2], [3, 3, 3], [4, 4, 4]) print(m == list(m2) and n == list(n2))#true
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













