Python在使用zip()遍历列表时不会修改值,但是在使用enumerate()时会修改值

时间:2019-01-28 03:11:42

标签: python list for-loop variables

为什么使用索引号进行迭代时Python的工作方式有所不同?例如,对于zip函数(在for循环中使用时没有索引),值不会存储在变量中。使用enumerate()函数(允许我在foor循环中使用“索引”)时,它通常会发生。

当我尝试在循环内外打印它时,不使用索引的解决方案的“ width”变量具有不同的值,这里的zip()函数用于处理列表中的两个列表。同时无需处理其索引:

tableData = [['apples', 'oranges', 'cherries', 'banana'],
            ['Alice', 'Bob', 'Carol', 'David'],
            ['dogs', 'cats', 'moose', 'goose']]

def printTable(myListOfLists):
    colWidths = [0] * len(myListOfLists)
    for lists, width in zip(myListOfLists, colWidths):
        for item in lists:
            if width < len(item):
                width = len(item)
        print(width) #This prints my 'width' rightly
    print(colWidths) #This prints my 'width' wrongly

printTable(tableData)

上面的代码产生以下不需要的输出:

8
5
5
[0, 0, 0]

但是,如果我使用enumerate()(生成索引以同时使用两个列表),则在for循环中修改的值将正确保存在width变量中,请参见代码示例:

tableData = [['apples', 'oranges', 'cherries', 'banana'],
            ['Alice', 'Bob', 'Carol', 'David'],
            ['dogs', 'cats', 'moose', 'goose']]

def printTable(myListOfLists):
    colWidths = [0] * len(myListOfLists)
    for index, lists in enumerate(myListOfLists):
        for item in lists:
            if colWidths[index] < len(item):
                colWidths[index] = len(item)
        print(colWidths[index]) #This prints my 'width' rightly
    print(colWidths) #This ALSO prints my 'width' rightly

printTable(tableData)

第二个输出是:

8
5
5
[8, 5, 5]

然后,请问如何使用zip()并修改我的“外部”变量?我究竟做错了什么?谢谢。

3 个答案:

答案 0 :(得分:2)

我相信,您想要实现的是从tableData获取给定子列表中最长项目的长度。为此,您可以从子列表中获取最长的字符串,然后像这样测量其长度:

tableData = [['apples', 'oranges', 'cherries', 'banana'],
             ['Alice', 'Bob', 'Carol', 'David'],
             ['dogs', 'cats', 'moose', 'goose']]


def printTable(myListOfLists):
    colWidths = []
    for sub_list in myListOfLists:
        longest_item = max(sub_list, key=len)
        colWidths.append(len(longest_item))
    print(colWidths)


printTable(tableData)

编辑并说明:

通过使用for lists, width in zip(myListOfLists, colWidths):

在每个周期中 1)单个列表,其中tableData中的字符串为lists。 2)整数,与colWidths一样,精确为0,width

然后,在对每个文本(如“苹果”,“橙子”等)进行迭代时。

您在这里做什么: width = len(item)就像是说“现在宽度不再是0,它是len(item),这样您就不会影响列表colWidths,因为您没有使用它,而是在进行操作此0值,与colWidths列表中的位置无关,它只是0,被“宽度”名称下的len(item)替换。

答案 1 :(得分:1)

这样,您将不会更改列表的值,而需要索引来更改实际值。

示例:

for e in [1, 2, 3]:
    e = 10  # this way is wrong 

data = [1, 2, 3]
for index, e in enumerate(data):
    e[index] = 50 # always it is needed an index  

解决问题的好方法:

tableData = [['apples', 'oranges', 'cherries', 'banana'],
             ['Alice', 'Bob', 'Carol', 'David'],
             ['dogs', 'cats', 'moose', 'goose']]


data = [len(max(e, key=len)) for e in tableData]

print(data)

tableData = [['apples', 'oranges', 'cherries', 'banana'],
            ['Alice', 'Bob', 'Carol', 'David'],
            ['dogs', 'cats', 'moose', 'goose']]

def printTable(myListOfLists):
    colWidths = [0] * len(myListOfLists)
    for index, row in enumerate(myListOfLists):
        colWidths[index] = len(max(row, key=len))
    print(colWidths)

printTable(tableData)

另一方面,您可以尝试一下。

for i, (a, b) in enumerate(zip(alist, blist)):
    print i, a, b

答案 2 :(得分:1)

enumerate是一种生成索引的Python方法(类似于for i in range(len(...):

colWidths = [0] * len(myListOfLists)
for index, lists in enumerate(myListOfLists):
    for item in lists:
        if colWidths[index] < len(item):
            colWidths[index] = len(item)

这里listsitem来自myListOfLists,但是您明确修改了colWidths列表。

在第一种情况下,您正在修改一个迭代变量,而不是源列表:

colWidths = [0] * len(myListOfLists)
for lists, width in zip(myListOfLists, colWidths):
    for item in lists:
        if width < len(item):
            width = len(item)

width是一个迭代变量。但是width = len(item)行为变量(名称)分配了一个新值,从而中断了它与源数组的链接。在下一次迭代中,width再次由迭代器设置。源列表colWidths不变。

此模式适用于简单情况:

alist = [1,2,3,4]
for i in alist:
   i = 5     # does nothing to alist

for i in range(4):
    alist[i] = 5    # changes an element of alist

对迭代变量的更改非常棘手。您必须了解它何时表示“可变”,而不是。并且了解分配给变量和修改对象(如列表)之间的区别。