2012-06-29 5 views
21

J'utilise Python depuis quelques temps et je découvre la façon "pythonique" de coder. J'utilise beaucoup de tuples dans mon code, la plupart d'entre eux sont des positions polaires ou cartésiennes.Lisibilité des tuples: [0,0] vs (0,0)

Je me suis retrouvé à écrire ceci:

window.set_pos([18,8]) 

au lieu de ceci:

window.set_pos((18,8)) 

pour se débarrasser de la double parenthèse que je trouve difficile à lire.

Il semble que python effectue automatiquement la conversion de type de liste à tuple, car mon code fonctionne correctement.

Mais est-ce un bon moyen de coder? Avez-vous un conseil de présentation que je pourrais utiliser pour écrire du code lisible?

Merci d'avance pour vos réponses sûrement éclairantes.

+0

J'aime bien la façon dont vous l'avez écrit aussi, semble plus bien défini. – jamylak

+9

Python ne "fait pas de conversion de type de liste à tuple". C'est [tapant le dard] (http://en.wikipedia.org/wiki/Duck_typing) en action: probablement 'window.set_pos' nécessite une séquence de deux éléments, mais pas nécessairement un 2-' tuple' (je dis sans doute puisque je ne sais pas où 'window.set_pos' vient ou ce qu'il fait). – Chris

+9

Réécrire la fonction pour prendre deux arguments au lieu d'un 2-tuple. –

Répondre

25

Je ferais attention de ne pas utiliser les listes en faveur des listes partout. Avez-vous déjà utilisé le module dis? Regardez ce que Python fait au niveau de bytecode quand vous faites un vers la liste faisant un tuple:

>>> def f(): 
...  x = [1,2,3,4,5,6,7] 
...  return x 
... 
>>> def g(): 
...  x = (1,2,3,4,5,6,7) 
...  return x 
... 
>>> import dis 
>>> dis.dis(f) 
    2   0 LOAD_CONST    1 (1) 
       3 LOAD_CONST    2 (2) 
       6 LOAD_CONST    3 (3) 
       9 LOAD_CONST    4 (4) 
      12 LOAD_CONST    5 (5) 
      15 LOAD_CONST    6 (6) 
      18 LOAD_CONST    7 (7) 
      21 BUILD_LIST    7 
      24 STORE_FAST    0 (x) 

    3   27 LOAD_FAST    0 (x) 
      30 RETURN_VALUE  
>>> 
>>> 
>>> dis.dis(g) 
    2   0 LOAD_CONST    8 ((1, 2, 3, 4, 5, 6, 7)) 
       3 STORE_FAST    0 (x) 

    3   6 LOAD_FAST    0 (x) 
       9 RETURN_VALUE 

Bien qu'il ne sera probablement jamais un problème dans une application graphique (comme exemple semble être), pour des raisons de performance vous pouvez faire attention à le faire partout dans votre code.

+1

Merci beaucoup, vous m'a convaincu! Je me soucie vraiment de la performance car mon application n'est pas une interface graphique mais un jeu avec une interface graphique. Vous êtes bytecode réponse détaillée est vraiment utile pour comprendre ce qui se passe en arrière-plan (je ne savais pas le module dis). –

+1

Je viens de chronométrer les deux fonctions: la version de la liste prend env. doubler le temps que la version tuple (2,1 vs 0,9 secondes pour 10 millions d'appels). Pour les collections à deux éléments, cependant, les différences sont plus faibles: 1,6 contre 0,9 secondes. –

+2

Ah, c'est vrai - j'avais oublié que les littéraux de tuple sont [pliés] (http://stackoverflow.com/a/8068248/577088). Si vous passez des littéraux (et non des tuples construits à partir de variables), cela pourrait faire une grande différence. – senderle

0

Si vous voulez insister sur le fait que votre paramètre est un tuple, vous pouvez explicity convertir:

window.set_pot(tuple([18, 18])) 
+4

Cela a l'air bien pire. – jamylak

4

OMI le seul avantage de l'utilisation (18,8) sur [18,8] est qu'un objet tuple est immuable et vous pouvez assurez-vous qu'il ne sera pas modifié dans la fonction, il est passé, tandis que [18,8] peut être facilement modifié.

4

Python n'effectue aucune conversion automatique de liste en ligne, à moins que la méthode set_pos ne le fasse explicitement. tuple et list ont des protocoles très similaires, donc ils ont tendance à être interchangeables dans ce protocole. Vous pouvez encore casser des choses, en particulier parce que le tuple est un immutable qui peut être haché, et une liste ne l'est pas.

Pour répondre à votre question, il suffit d'écrire

window.set_pos((18,18)) 

espaces appropriés font des miracles avec le style de codage.

+4

PEP-8 conseille de ne pas faire cela: http://www.python.org/dev/peps/pep-0008/#pet-peeves – jamylak

+1

@jamylak: d'accord, et je suis d'accord avec la suggestion du PEP, mais c'est un cas qui peut valoir l'exception. –

+0

@jamylak Cela n'est pas imposé par le langage, ce qui signifie que c'est juste un style de codage que l'auteur (ou les auteurs) de Python aime. Ce n'est pas le style de codage, et ne devrait jamais être considéré comme tel. Il suffit de les regarder comme de bonnes directives, et soyez prêt à les casser quand elles nuisent à la lisibilité - comme dans ce cas. – Izkata

12

Vous dites

Il semble que python fait automatiquement la conversion du type de liste tuple

C'est douteux. Puisque les listes et les tuples sont tous les deux sequence types, ils implémentent tous les mêmes comportements, et quelle que soit la bibliothèque GUI que vous utilisez, vous n'avez besoin d'aucun des comportements list-only.

Il est probablement bien de le faire dans de nombreux cas, mais notez que les listes ne prennent un peu plus d'espace que tuples:

>>> sys.getsizeof((1, 2)) 
72 
>>> sys.getsizeof([1, 2]) 
88 

Et peut-être plus lent que tuples certaines choses:

>>> lst, tup = [1, 2], (1, 2) 
>>> def unpack(x): 
...  a, b = x 
...  
>>> %timeit unpack(tup) 
10000000 loops, best of 3: 163 ns per loop 
>>> %timeit unpack(lst) 
10000000 loops, best of 3: 172 ns per loop 

ce sont très petites différences qui ne sera pas question jusqu'à des échelles beaucoup plus - comme dans milliards des appels - s o le compromis pourrait en valoir la peine.

Pourtant, je ne vois pas les gens le font très souvent. Cela semble être une bonne astuce de lisibilité, mais cela pourrait avoir des conséquences inattendues dans certaines circonstances. Par exemple, si vous transmettez une liste que vous avez l'intention d'utiliser plus tard, vous devez faire attention à ne pas la modifier dans la fonction. Enfin, comme le souligne à juste titre J.F. Sebastian, les tuples et les listes tendent à signifient des choses légèrement différentes; les utiliser de manière non conventionnelle pourrait nuire à la lisibilité que vous recherchez.

+0

Merci pour votre réponse précise! Je sais que cela peut sembler un peu étrange, mais je suis ravi de l'idée d'utiliser un objet inapproprié uniquement à des fins de lisibilité. Ma méthode "set_pos" décompresse simplement l'argument en deux variables, mais est utilisée la plupart du temps dans une boucle et je m'intéresse aux problèmes de performance. Est-ce que 14 ns a beaucoup d'importance? –

+0

Non, 14ns n'aura aucune importance quand il s'agit de régler la position de votre fenêtre. –

8

Je doute sérieusement que les tuples par rapport aux listes font une différence notable dans les performances dans votre cas. Ne faites pas de micro-optimisations, sauf si votre profileur le dit. La lisibilité est une priorité.

list et tuple sont tous les deux sequence types.

Sémaniquement les tuples peuvent être préférables (voir Tuples have structure, lists have order). La position est un objet unique qui a des attributs x, y.

Visuellement les listes pourraient être plus faciles à lire dans ce cas.

Quoi que vous choisissiez juste être cohérent.

Vérifiez si window prend en charge:

window.pos = 18, 8 

Une façon de mettre en œuvre est de faire le pos un property et lier set_pos() comme compositeur.

+2

+1 pour la sémantique des tuples par rapport aux listes, ce qui devrait presque toujours être le facteur décisif à utiliser. – FogleBird

Questions connexes