Pythonic交换两个列表的元素

15

我发现我需要在Python中进行交换,于是我写了以下代码:

arr[first], arr[second] = arr[second], arr[first]

我认为这不太符合Python的风格。有人知道如何更优雅地在Python中进行交换吗?

编辑: 我认为另一个示例可以说明我的疑惑:

self.memberlist[someindexA], self.memberlist[someindexB] = self.memberlist[someindexB], self.memberlist[someindexA]

这是Python中唯一可用的交换解决方案吗?


你不喜欢什么?有什么问题吗?你希望有什么可以更短一些的东西吗?你能提供伪代码来说明你认为更好的是什么吗? - S.Lott
2
这是一种糟糕的交换写法,需要重复每个表达式,但这是Python能做的最好的方式。C++ 的swap(a, b) 是一种干净、不重复的交换方式,但Python不支持那种间接级别,所以它无法实现。这只是需要接受的事实;每种语言都有其局限性,这只是其中一个较小的局限。 - Glenn Maynard
5个回答


14

在你的示例代码中,我可能会改变一件事情:如果你要多次使用像self.memberlist这样的长名称,通常更易读的方法是先给它分配一个较短的别名。因此,例如,可以使用以下较短、易于阅读的代码:

self.memberlist[someindexA], self.memberlist[someindexB] = self.memberlist[someindexB], self.memberlist[someindexA]

你可以编写如下代码:

L = self.memberlist
L[someindexA], L[someindexB] = L[someindexB], L[someindexA]

请记住Python是按引用工作的,所以L指向完全相同的对象,与self.memberlist不是副本(同样,无论列表有多长,赋值都非常快,因为它不会被复制,只是增加了一个引用)。

我认为没有必要增加任何进一步的复杂性,尽管当然可以轻易地构思出一些花哨的东西,例如(对于a,b“正常”的索引>=0):

def slicer(a, b):
  return slice(a, b+cmp(b,a), b-a), slice(b, a+cmp(a,b), a-b)

back, forth = slicer(someindexA, someindexB)
self.memberlist[back] = self.memberlist[forth]

我认为弄清这些“高级”用法是一个不错的想法,有用的头脑锻炼和很有趣——我建议感兴趣的读者,在掌握了一般思路后,重点关注那些+cmp的作用以及它们如何使三种可能性(a>b、a<b、a==b)的工作[[虽然对于负索引不起作用——为什么不起作用,slicer需要如何更改来解决这个问题?]]. 但在生产代码中使用这种花哨的方法通常会过度设计且毫无必要,会让事情变得更加混乱和难以维护,而不如简单明了的方法。

记住,简单胜于复杂


1

很难想象如何使它更优雅:使用一个假设的内置函数... swap_sequence_elements(arr, first, second) 优雅吗?也许是,但这已经进入了YAGGI领域——你不会得到它;-)——而且函数调用开销应该会让你放弃自己实现它。

你所拥有的比行内方式更加优雅:

temp = arr[first]
arr[first] = arr[second]
arr[second] = temp

而且(額外的獎勵!)速度更快(基於一個不太合理的假設,即字節碼 ROT_TWO 比 LOAD_FAST 加 STORE_FAST 更快)。

1

a, b = b, a 这行代码非常简短,除了变量名只有三个字符。这是最Pythonic的写法之一。

另一种方法是使用临时变量:

self.memberlist[someindexA], self.memberlist[someindexB] = self.memberlist[someindexB], self.memberlist[someindexA]

..变成了..

temp = self.memberlist[someindexB]
self.memberlist[someindexB] = self.memberlist[someindexA]
self.memberlist[someindexA] = temp

...我认为更加混乱和不明显

另一种方式,使用较长的变量名可能会更易读:

a, b = self.memberlist[someindexA], self.memberlist[someindexB]
self.memberlist[someindexA], self.memberlist[someindexB] = b, a

-1
我想你可以利用切片符号的步长参数来实现这样的操作:
myarr[:2] = myarr[:2][::-1]
不过我不确定这样做是否更清晰或者更符合Pythonic...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接