编写类似于 reverse() 函数的 Python 代码

Writing Python code that works like the reverse() function

我想分解 reverse() 函数并将其写成代码以供练习。我最终想出了如何去做(向后遍历原始列表并附加到新的 'reversed' 列表)但想知道为什么这不起作用。

def reverse(list):
    newlist = []
    index = 0
    while index < len(list):
        newlist[index] = list[(len(list)) - 1 - index]
        index = index + 1
    return newlist

list = [1, 2, 3, 4, 5]
print(reverse(list))

不能为长度为 0 的列表分配任意索引。这样做会引发 IndexError。由于您是按顺序分配元素,因此您可以只进行追加而不是对索引进行分配:

newlist.append(l[(len(l)) - 1 - index])

附加修改列表并自动增加其长度。

让您的原始代码工作的另一种方法是更改​​ newlist 的初始化,以便它有足够的长度来支持您的索引操作:

newlist = [None for _ in range(len(l))]

我还想指出,以内置类型和函数命名事物并不是一个好主意。这样做会影响内置函数的功能。

首先不要覆盖内置函数(list 在你的情况下)第二个 newlist 有一个 len 为 0 因此不能被索引访问。

def reverse(mylist):
    newlist = [0] * len(mylist)
    index = 0
    while index < len(mylist):
        newlist[index] = mylist[(len(mylist)) - 1 - index]
        index = index + 1
    return newlist

mylist = [1, 2, 3, 4, 5]
print(reverse(mylist))

您可以创建一个列表,其值与输入列表的长度相同,就像这样

newlist = [0] * len(mylist)

您需要使用 list.appendnewlist[0] 是一个有效的操作,如果列表中至少有一个元素,但 newlist 在第一次迭代中是空的。此外,list 不是变量的好名称,因为有一个 python 内置容器同名:

def reverse(lst):
    newlist = []
    index = 0
    while index < len(lst):
        newlist.append(lst[(len(list)) - 1 - index])
        index += 1
    return newlist

list = [1, 2, 3, 4, 5]
print(reverse(list))

在 Python 中,如果索引不在 0 和列表长度 - 1 的范围内,则不能 access/update 列表的元素。

在您的例子中,您正试图分配给 0 处的元素,但列表为空。所以,它没有索引 0。这就是它失败并显示错误的原因,

IndexError: list assignment index out of range

相反,您可以使用 append 函数,像这样

    newlist.append(list[(len(list)) - 1 - index])

除此之外,您还可以使用range函数像这样倒数

for index in range(len(list) - 1, -1, -1):
    newlist.append(list[index])

您甚至不必自己增加 indexfor 循环会处理它。


正如@abarnert 所建议的,您实际上可以迭代列表并每次都在开头添加元素,就像这样

>>> def reverse(mylist):
...     result = []
...     for item in mylist:
...         result.insert(0, item)
...     return result
... 
>>> reverse([1, 2, 3, 4, 5])
[5, 4, 3, 2, 1]

如果你想创建一个新的反向列表,你可能不必自己写一个函数,而是可以使用slicing notation来创建一个新的反向列表,像这样

>>> mylist = [1, 2, 3, 4, 5]
>>> mylist[::-1]
[5, 4, 3, 2, 1]

但这不会改变原始对象。

>>> mylist = [1, 2, 3, 4, 5]
>>> mylist[::-1]
[5, 4, 3, 2, 1]
>>> mylist
[1, 2, 3, 4, 5]

如果要改变原来的对象,只需将切片赋值回原来对象的切片,像这样

>>> mylist
[1, 2, 3, 4, 5]
>>> mylist[:] = mylist[::-1]
>>> mylist
[5, 4, 3, 2, 1]

注: reversed actually returns a reverse iterator object, not a list. So, it doesn't build the entire list reversed. Instead it returns elements one by one when iterated with next协议。

>>> reversed([1, 2, 3, 4, 5])
<list_reverseiterator object at 0x7fdc118ba978>
>>> for item in reversed([1, 2, 3, 4, 5]):
...     print(item)
...     
... 
5
4
3
2
1

因此,您可能希望将其设为 generator function,像这样

>>> def reverse(mylist):
...     for index in range(len(mylist) - 1, -1, -1):
...         yield mylist[index]
...     
... 
>>> reverse([1, 2, 3, 4, 5])
<generator object reverse at 0x7fdc118f99d8>

所以 reverse 函数 returns 一个生成器对象。如果你想要一个列表,那么你可以用 list 函数创建一个,像这样

>>> list(reverse([1, 2, 3, 4, 5]))
[5, 4, 3, 2, 1]

如果你只是要一个一个地处理它,那么用一个 for 循环迭代它,就像这样

>>> for i in reverse([1, 2, 3, 4, 5]):
...     print(i)
...     
... 
5
4
3
2
1

可能会检查一下:

def reverse(lst):
     newList = []
     countList = len(lst) - 1
     for x in range(countList,-1,-1):

         newList.append(lst[x])
     return newList

def main():
    lst = [9,8,7,6,5,4,2]
    print(reverse(lst))

main()

要编写您尝试编写的函数,请参阅

但这不是 reverse 的工作方式,也不是它的作用。它不是创建新列表,而是就地修改现有列表。

如果您考虑一下,这很简单:只需遍历一半索引,对于每个索引 N,交换左起第 N 个和右起第 N 个。*

因此,坚持使用您现有的框架:

def reverse(lst):
    index = 0
    while index < len(lst)/2:
        lst[index], lst[len(lst) - 1 - index] = lst[len(lst) - 1 - index], lst[index]
        index = index + 1

附带说明一下,像这样使用 while 循环几乎总是一个坏主意。如果你想遍历一个数字范围,只需使用 for index in range(len(lst)):。除了将三行代码减少为一行并使您所做的事情更加明显之外,它还删除了多个您可能会犯简单但调试起来很痛苦的错误的地方。

另外,请注意,在大多数情况下,在 Python 中,使用负数索引来表示 "from the right edge" 比自己计算更容易,而且它通常会删除一个可能的位置你很容易犯一个痛苦的错误。但在这种特殊情况下,它实际上可能不会更容易出错……


* 您必须确保考虑到边缘情况。对于奇数列表,您是否将中间元素与其自身交换并不重要,但只要确保您不会以错误的方式舍入并使一个元素走得太远或太短。这是学习如何编写好的单元测试的好机会……