Python zip:如何在Python中从Iterables创建Iterator

425 阅读12分钟

Python Zip Example Tutorial

zip()函数是一个容器,里面存放着实际数据。zip()函数返回一个基于可迭代对象的图元的迭代器。如果给定的迭代器有不同的长度,元素最少的迭代器决定了新迭代器的长度。

Python zip

zip()是一个内置的Python函数,它可以创建一个迭代器,将两个或多个可迭代的元素聚合起来。它把可迭代的元素作为输入,并返回迭代器 。 zip()方法返回zip对象,即图元的迭代器,其中每个传递的迭代器中的第一个项目被配对在一起。然后,每个给定的迭代器中的第二项被配对在一起。

因此, zip()函数接收迭代项(可以是零或更多),根据传递的迭代项制作一个聚合项的迭代器,并返回图元的迭代器。

zip()在内置命名空间中可用。

如果你使用dir()函数来检查 __builtins__,那么你会在列表的最后看到 zip() 。

print(dir(__builtins__))

你会看到长长的列表,但你会在最后找到zip。

如果zip python函数没有得到可迭代的项目,它将返回空的迭代器。

如果你使用的是IPython,那么输入zip?并查看zip()的内容。

如果你没有使用IPython,请安装它:"pip3 install ipython" ,因为我使用Python 3。对于Python3用户,pip install ipython 就可以了。

Python中的zip()函数 的语法如下。

zip(*iterables)

# or

zip(

zip()函数需要。

iterables- 可以是内置的迭代变量(如列表字符串dict)或用户定义的迭代变量(具有 __iter__方法的对象)。

zip()函数返回基于iterable对象的图元的迭代器。

  1. 如果在zip函数上没有传递参数,zip()返回空的迭代器。
  2. 如果向zip函数传递了一个迭代对象,zip()返回1-图元的迭代器。意思是,每个元组中的项目数是1。
  3. 如果传递多个迭代器,第i个元组包含第i个假设,并给出两个迭代器,一个迭代器包含3个,另一个包含5个元素。那么,一个返回的迭代器有三个图元。这是因为当最短的迭代器被用完时,迭代器就会停止。

在Python中检查zip对象

如果你使用带n个参数的zip(),该函数将返回产生长度为n的图元的迭代器,我们可以使用Python type()函数来确定其类型。

#app.py

numbers = [11, 21, 46]
letters = ['e', 'k', 'a']
zipped = zip(numbers, letters)
print(type(zipped))

输出

python3 app.py
<class 'zip'>

在这里,你使用zip(numbers, letters)来创建迭代器,产生形式为(x, y)的图元

x值取自数字,y值取自字母。

注意Python zip()函数是如何返回迭代器的。因此,要检索一个最终的列表对象,你需要使用 list() 来消耗迭代器。

在 Python zip() 中不传递参数

你调用 zip() 时没有参数,所以你的 zipped 变量持有一个空的迭代器。如果你用 list() 消耗迭代器,那么你也会看到一个空列表。

请看下面的代码。

# app.py

zipped = zip()
print(list(zipped))

输出

python3 app.py
[]

你也可以强迫空迭代器直接产生一个元素。在这种情况下,你会得到一个 StopIteration 异常。

# app.py

zipped = zip()
next(zipped)

输出

python3 app.py
Traceback (most recent call last):
  File "app.py", line 2, in 
    next(zipped)
StopIteration

当你对 zipped 调用 next() 时,Python 试图检索下一个项目。然而,由于 zipped 持有空的迭代器,没有什么可以拉出来,所以 Python 会引发 StopIteration 异常。

传递一个参数

Python zip() 函数可以只接受一个参数,并返回一个迭代器,产生一系列的 1-项目图元。

a = [11, 21, 19]

zippedObj = zip(a)

data = list(zippedObj)
print(data)

输出

[(11,), (21,), (19,)]

你看到,得到的图元的长度总是等于你作为参数传递的迭代器的数量。让我们给出三个迭代器。

a = [11, 21, 19]
b = ['hello', 'world', 'song']
c = [True, False, True]

zippedObj = zip(a, b, c)

data = list(zippedObj)
print(data)

输出

[(11, 'hello', True), (21, 'world', False), (19, 'song', True)]

这里,你用三个迭代变量(字符串、整数和布尔的列表)调用了Python zip方法,所以得到的图元有三个项目。

在Python字符串中使用zip()

如果你正在处理像字符串这样的序列,你的迭代变量保证从左到右被评估。所以让我们定义两个字符串,把它们传给zip()函数,然后看看输出。

strA = 'Python'
strB = 'Go'
zippedStr = zip(strA, strB)
data = str(zippedStr)
print(data)
print(type(data))

输出

<zip object at 0x103e46940>
<class 'str'>

使用Python集的zip()函数

如果你在处理像集合这样的序列,结果可能会很奇怪。例如,如果两个集合中有三个项目。现在,你对列表进行压缩,并将压缩后的对象转换回列表,但这次,值会失去它们的顺序。

setA = {'x', 'y', 'z'}
setB = {11, 21, 19}
zippedObj = zip(setA, setB)
listF = list(zippedObj)
print(listF)

输出

[('y', 19), ('z', 11), ('x', 21)]

在这个例子中,setA 和 setB 是集合对象,它们不以任何特定的顺序保持其项目。不幸的是,这意味着由 zip() 返回的图元将有随机配对的项目。

如果你要用 Python zip() 函数来处理像 sets 这样的无序迭代对象,这是要考虑的问题。

在 Python list 中使用 zip()

zip()函数将像下面这样的列表。

a: a1 a2 a3 a4 a5 a6 a7...
b: b1 b2 b3 b4 b5 b6 b7...
c: c1 c2 c3 c4 c5 c6 c7...

并将它们 "压缩 "成一个列表,其条目是3个图元(ai, bi, ci)。想象一下,从左到右水平地画一条拉链。

app.py 文件里面写下以下代码。

# app.py

numList = [19, 21, 46]
strList = ['one', 'two', 'three']

outputA = zip(numList, strList)
print(list(outputA))

outputB = zip(strList, numList)
print(list(outputB))

其输出结果如下。

Python Zip Example

我们也可以将 输出转换 为元组。请看下面的代码。

# app.py

numList = [19, 21, 46]
strList = ['one', 'two', 'three']

outputA = zip(numList, strList)
print(tuple(outputA))

outputB = zip(strList, numList)
print(tuple(outputB))

输出结果如下。

➜  pyt python3 app.py
((19, 'one'), (21, 'two'), (46, 'three'))
(('one', 19), ('two', 21), ('three', 46))
➜  pyt

Python zip 两个列表

在 python 3.0 中,zip 方法返回 zip 对象。

你可以通过调用 list(zip(a, b))从它那里得到一个列表。

如果你想把列表合并成一个图元的列表,或者压缩两个列表,你可以使用 zip() 方法。pythonic 的方法是这样的。

# app.py
listA = [19, 21, 46]
listB = ['one', 'two', 'three']
merge_list = zip(listA, listB)
print(list(merge_list))

请看输出结果。

➜  pyt python3 app.py
[(19, 'one'), (21, 'two'), (46, 'three')]
➜  pyt

你必须知道 zip() 函数会在最短列表的结尾处停止,这可能不一定是你想要的输出结果。

itertools模块定义了一个zip_longest()方法,它在最长列表的末端停止,用你提供的参数来填补缺失的值。

使用zip()解压缩值

我们也可以从Python zip函数中提取数据。如果我们想删除zip,我们必须使用同样的**zip()**函数。但是我们必须在你从压缩变量得到的那个列表前面加上星号(*)。

我们也可以解压缩numListstrList。 请看下面的例子。

# app.py

numList = [19, 21, 46]
strList = ['one', 'two', 'three']

outputA = zip(numList, strList)

x, y = zip(*outputA )
print('numList = ', x)
print('strlist = ', y)

输出结果如下。

➜  pyt python3 app.py
numList =  (19, 21, 46)
strlist =  ('one', 'two', 'three')
➜  pyt

*操作符可以和zip一起使用来解压列表。

你可以使用list() 函数从压缩的变量中获得列表。然而,这将返回几个图元。这个数量将根据 zip 函数在压缩数据时的参数数量而有所不同。

如果传递的迭代器有不同的长度,拥有最少项目的迭代器决定新迭代器的长度。请看下面的例子。

# app.py

numList = [19, 21, 46, 29]
strList = ['one', 'two', 'three']

outputA = zip(numList, strList)

print(list(outputA))

numList四个项目,而strList三个元素。所以长度是不匹配的。让我们看看输出结果。

➜  pyt python3 app.py
[(19, 'one'), (21, 'two'), (46, 'three')]
➜  pyt

Zip三个迭代器

让我们举个例子,我们可以使用三个迭代器,然后对其使用zip函数。

# app.py

numList = [19, 21, 46]
strList = ['one', 'two', 'three']
setList = {'A1', 'B1', 'C1'}

outputA = zip(numList, strList, setList)

print(list(outputA))

其输出结果如下。

➜  pyt python3 app.py
[(19, 'one', 'C1'), (21, 'two', 'A1'), (46, 'three', 'B1')]
➜  pyt

我们取了三个不同的变量,然后使用zip()函数并将其转换为可迭代的变量。

比较Python 2 zip() 和Python 3 zip()

zip()函数在两个版本的Python中的工作方式不同。

在 Python 2 中,zip() 方法返回一个图元的列表。输出的列表被截断为最短输入迭代器的长度。如果你调用 zip() 没有参数,你会得到一个空的列表作为回报。

请看下面 Python2 的代码。

zipped = zip(range(3), 'WXYZ')

print(zipped)

输出

python2 app.py
[(0, 'W'), (1, 'X'), (2, 'Y')]

在这种情况下,你对Python zip()方法的调用返回一个被截断为Z值的图元列表。

现在,让我们调用一个没有参数的 zip() 方法。

zipped = zip()

print(zipped)

输出

python2 app.py
[]

当你调用没有参数的zip()方法时,你得到一个空列表。

如果你没有向zip()提供参数,该函数返回一个空的迭代器。

zipped = zip()

print(zipped)

输出

python3 app.py
<zip object at 0x10c3a09c0>

当我们在Python 3中没有给zip()函数提供参数时,你将得到一个空的迭代器。

如果你经常使用Python 2,那么请注意,对长的输入迭代器使用zip()方法会无意中消耗大量的内存。在这种情况下,可以考虑使用itertools.izip(*iterables)代替。这个函数创建迭代器,将每个迭代器中的项目聚合起来。它产生的效果与Python 3中的zip()函数相同。但我建议将Python从2更新到3,并使用Python 3 zip()函数。

循环处理多个迭代变量

Python zip()函数的最大用途是在多个迭代变量上循环。如果你需要在多个列表、图元或任何其他序列上进行迭代,那么你很可能会在zip()上退步。

并行遍历列表

zip()函数允许我们对两个或更多的迭代对象进行并行迭代。由于zip()函数生成图元,你可以在for循环头中解包这些图元。

dataStr = ['x', 'y', 'z']
dataInt = [11, 21, 19]

for a, b in zip(dataStr, dataInt):
    print(f'String: {a}')
    print(f'Integer: {b}')

输出

String: x
Integer: 11
String: y
Integer: 21
String: z
Integer: 19

为了在控制台中打印数值,我们对字符串进行了格式化

在这里,你遍历了由zip()返回的一系列图元,并将元素解包到a和b中。当你将zip()、for循环和图元解包结合起来时,你可以得到一个方便的、Pythonic的行话,用于一次遍历两个或多个迭代变量。

你也可以在一个单一的for循环中遍历两个迭代变量。考虑一下下面的例子,它有三个输入迭代变量。

dataStr = ['x', 'y', 'z']
dataInt = [11, 21, 19]
dataSpecial = ['&', '$', '@']

for a, b, c in zip(dataStr, dataInt, dataSpecial):
    print(f'String: {a}')
    print(f'Integer: {b}')
    print(f'Special: {c}')

输出

String: x
Integer: 11
Special: &
String: y
Integer: 21
Special: $
String: z
Integer: 19
Special: @

在这个例子中,你用三个迭代变量的zip()来创建并返回生成3项图元的迭代器。这使我们能够一次性地迭代所有三个迭代变量。在Python的zip()函数中,你可以使用的迭代器的数量没有限制。

使用zip()并行遍历字典

从Python 3.6及以后,字典是有序的集合,这意味着它们会按照先导的顺序保持它们的项目。如果你利用这一点,你可以使用Python zip()函数安全而连贯地遍历多个字典。

dictA = {
    'name': 'Homer',
    'age': 50,
    'type': 'fat'
}

dictB = {
    'name': 'Bart',
    'age': 10,
    'type': 'medium'
}

for (key1, val1), (key2, val2) in zip(dictA.items(), dictB.items()):
    print(key1, '->', val1)
    print(key2, '->', val2)

输出

name -> Homer
name -> Bart
age -> 50
age -> 10
type -> fat
type -> medium

这里,你并行地迭代了dictA和dictB。在这种情况下,zip()用两个字典的元素创建图元。然后,你可以解开每个元组,并在同一时间获得对两个字典中的项目的访问--孩子们的东西。

你还可以使用zip()函数来并行地迭代集合。然而,你必须考虑到,与 Python 3.6 中的字典不同,集合并不按顺序保留它们的项目。如果你忘记了这个细节,你的程序的最终输出可能不完全是你想要或期望的那样。

并行排序

假设你要合并两个列表(一个是ints列表,一个是strings列表),并同时对它们进行排序。要做到这一点,我们可以使用 zip() 和sorted()方法,如下所示。

dataStr = ['z', 'y', 'w', 'x']
dataInt = [19, 21, 18, 46]

zippyData = zip(dataInt, dataStr)
data = list(zippyData)
print(data)
print(sorted(data))

输出

[(19, 'z'), (21, 'y'), (18, 'w'), (46, 'x')]
[(18, 'w'), (19, 'z'), (21, 'y'), (46, 'x')]

在这种情况下,sorted()运行zip()生成的迭代器,并按整数对项目进行排序,一次完成。这种方式可以更快一点,因为你只需要两个函数调用:zip()和sorted()。

使用sorted(),你也在编写对其他程序员有意义的更通用的代码。例如,这将使你能够对任何序列进行排序,而不仅仅是列表。

总结

在这个深度教程中,你已经学会了如何使用 Python 的 zip() 函数。zip() 可以接收多个迭代项作为输入,并返回一个迭代器,从每个参数中创建具有成对项的图元。当你需要在单个for循环中处理多个迭代变量并同时对它们的项目执行一些操作时,最后的迭代器会很有帮助。本教程就到此为止。

推荐的帖子

Python ascii()

Python bin()

Python bool()

Python any()

Python all()

The postPython zip: How to Create Iterator from Iterables in Pythonappeared first onAppDividend.