Pythonic Swap?

Я обнаружил, что мне нужно выполнить обмен в python, и я пишу что-то вроде этого.

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

Я полагаю, что это не так пифонично. Кто-нибудь знает, как сделать обмен в python более элегантным?

EDIT: Я думаю, что еще один пример покажет мои сомнения.

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

- это единственное доступное решение для swap в python? Я много искал, но не нашел приятного ответа...

Ответы

Ответ 1

Единственное, что я могу изменить в вашем примере кода: если вы собираетесь использовать некоторое длинное имя, например 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 нужно было изменить, чтобы исправить это?]], Но использование такого причудливого подхода в производственном коде, как правило, было бы излишним и совершенно необоснованным, что делало вещи более мрачными и сложными для поддержания, чем простой и понятный подход.

Помните, просто лучше, чем сложный!

Ответ 3

Трудно представить, как это можно было бы сделать более элегантным: используя гипотетическую встроенную функцию... swap_sequence_elements(arr, first, second) элегантный? может быть, но это на территории YAGGI - вы не собираетесь ее получать;-) - и служебные вызовы функции должны/должны были бы отвлечь вас от реализации.

То, что у вас есть, намного более элегантно, чем альтернативный способ:

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

и (бонус!) тоже быстрее (в необоснованном предположении, что байт-код ROT_TWO быстрее, чем LOAD_FAST плюс a STORE_FAST).

Ответ 4

a, b = b, a примерно такой же короткий, как вы получите, это всего три символа (кроме имен переменных). Это примерно как Python'ы, поскольку вы получите

Одним из альтернатив является обычная переменная use-a-temp:

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

Ответ 5

Я полагаю, вы могли бы воспользоваться аргументом шага нотации slice, чтобы сделать что-то вроде этого:

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

Я не уверен, что это более ясное или более питоническое, хотя...