Pythonic Swap?

走远了吗. 提交于 2019-12-01 03:07:06
Alex Martelli

The one thing I might change in your example code: if you're going to use some long name such as self.memberlist over an over again, it's often more readable to alias ("assign") it to a shorter name first. So for example instead of the long, hard-to-read:

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

you could code:

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

Remember that Python works by-reference so L refers to exactly the same object as self.memberlist, NOT a copy (by the same token, the assignment is extremely fast no matter how long the list may be, because it's not copied anyway -- it's just one more reference).

I don't think any further complication is warranted, though of course some fancy ones might easily be conceived, such as (for a, b "normal" indices >=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]

I think figuring out these kinds of "advanced" uses is a nice conceit, useful mental exercise, and good fun -- I recommend that interested readers, once the general idea is clear, focus on the role of those +cmp and how they make things work for the three possibilities (a>b, a<b, a==b) [[not for negative indices, though -- why not, and how would slicer need to change to fix this?]]. But using such a fancy approach in production code would generally be overkill and quite unwarranted, making things murkier and harder to maintain than the simple and straightforward approach.

Remember, simple is better than complex!

a, b = b, a

Is a perfectly Pythonic idiom. It is short and readable, as long as your variable names are short enough.

It's difficult to imagine how it could be made more elegant: using a hypothetical built-in function ... swap_sequence_elements(arr, first, second) elegant? maybe, but this is in YAGGI territory -- you aren't going to get it ;-) -- and the function call overhead would/should put you off implementing it yourself.

What you have is much more elegant than the alternative in-line way:

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

and (bonus!) is faster too (on the not unreasonable assumption that a bytecode ROT_TWO is faster than a LOAD_FAST plus a STORE_FAST).

a, b = b, a is about as short as you'll get, it's only three characters (aside from the variable names).. It's about as Python'y as you'll get

One alternative is the usual use-a-temp-variable:

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

..becomes..

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

..which I think is messier and less "obvious"

Another way, which is maybe a bit more readable with long variable names:

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

I suppose you could take advantage of the step argument of slice notation to do something like this:

myarr[:2] = myarr[:2][::-1]

I'm not sure this is clearer or more pythonic though...

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!