Pythonic Swap? - PullRequest
       11

Pythonic Swap?

15 голосов
/ 19 июля 2009

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

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

Полагаю, это не так уж и питонно. Кто-нибудь знает, как сделать обмен в Python более элегантным?

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

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

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

Ответы [ 5 ]

17 голосов
/ 19 июля 2009
a, b = b, a

Совершенно Pythonic идиома. Он короткий и читаемый, если ваши имена переменных достаточно короткие.

14 голосов
/ 19 июля 2009

Одна вещь, которую я мог бы изменить в вашем примере кода: если вы собираетесь использовать какое-то длинное имя, такое как 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 Помните, проще, чем сложнее !

1 голос
/ 19 июля 2009

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

Одной из альтернатив является обычная переменная 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
1 голос
/ 19 июля 2009

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

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

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

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

0 голосов
/ 20 июля 2009

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

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

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

...