2009-07-19 7 views
15

J'ai trouvé que je devais effectuer un échange en python et j'écris quelque chose comme ça. Je suppose que ce n'est pas tellement pythonique. Est-ce que quelqu'un sait comment faire un échange en python plus élégant?Pythonic Swap?

EDIT: Je pense qu'une autre exemple montrera mes doutes

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

est-ce la seule solution disponible pour le swap en python? Je ne cherchais beaucoup mais n'a pas trouvé une belle réponse ...

+0

Qu'est-ce que vous n'aimez pas? Qu'est ce qui ne va pas avec ça? Qu'aimeriez-vous qui pourrait être plus court? Pourriez-vous fournir un pseudo-code pour ce que vous pensez que serait mieux? –

+2

C'est une manière terrible d'écrire un échange, d'avoir à répéter chaque expression, mais c'est le meilleur que peut faire Python. Le swap de C++ (a, b) est la manière propre et non répétitive de faire des swaps, mais Python ne supporte pas ce niveau d'indirection, donc il ne peut pas le faire. Juste quelque chose à vivre avec; chaque langue a ses limites, et c'est une mineure. –

Répondre

14

La seule chose que je pourrais changer dans votre code d'exemple: si vous allez utiliser un nom long, comme self.memberlist sur Encore une fois, il est souvent plus lisible à alias ("attribuer") à un nom plus court en premier. Ainsi, par exemple au lieu de long, difficile à lire:

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

vous pourriez code:

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

Rappelez-vous que Python fonctionne par référence si L désigne exactement le même objet que self.memberlist, PAS une copie (du même coup, l'assignation est extrêmement rapide quelle que soit la longueur de la liste, car elle n'est pas copiée de toute façon - c'est juste une référence de plus).

Je ne pense pas que toute complication supplémentaire est justifiée, même si bien sûr certains pourraient facilement ceux de fantaisie se concevoir, comme (a, b indices « normaux » >=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] 

Je pense comprendre out ces types d'utilisations "avancées" est une belle vanité, exercice mental utile, et bon amusement - je recommande que les lecteurs intéressés, une fois l'idée générale est claire, se concentrer sur le rôle de ceux +cmp et comment ils font fonctionner les choses pour le trois possibilités (a> b, a < b, a == b) [[pas pour les indices négatifs, cependant - pourquoi pas, et comment slicer besoin de changer pour résoudre ce problème?]]. Mais l'utilisation d'une telle approche sophistiquée dans le code de production serait généralement exagérée et injustifiée, rendant les choses plus difficiles à maintenir que l'approche simple et directe.

Rappelez-vous, simple is better than complex!

16
a, b = b, a 

Is a perfectly Pythonic idiom. Il est court et facile à lire, aussi longtemps que vos noms de variables sont assez courts.

+0

http://www.google.co.il/search?q=python+swap&ie=utf-8&oe=utf-8&aq=t&rls=com.ubuntu:en-US:unofficial&client=firefox-a –

1

Il est difficile d'imaginer comment il pourrait être rendu plus élégant: en utilisant une fonction intégrée hypothétique ... swap_sequence_elements(arr, first, second) élégant? peut-être, mais c'est dans le territoire de YAGGI - vous n'allez pas l'obtenir ;-) - et la surcharge de l'appel de fonction devrait/devrait vous empêcher de l'appliquer vous-même.

Qu'est-ce que vous avez est beaucoup plus élégante que l'alternative en ligne ainsi: (! Prime)

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

et est plus rapide aussi (sur l'hypothèse pas déraisonnable qu'un bytecode ROT_TWO est plus rapide qu'un LOAD_FAST, plus un STORE_FAST).

1

a, b = b, a est à peu près aussi court que vous aurez, il n'y a que trois personnages (à part les noms de variables) .. Il est à peu près aussi Python'y que vous aurez

Une alternative est l'utilisation- habituelle une température 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 Je pense est messier et moins "évident"

Une autre façon, ce qui est peut-être un peu plus facile à lire avec de longs noms de variables:

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

Je suppose que vous pourriez profiter de l'argument de l'étape de la notation de la tranche pour faire quelque chose comme ceci:

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

Je Je ne suis pas sûr que cela soit plus clair ou plus pythonique ...

Questions connexes