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