2014-06-06 1 views
2

Je suis un programmeur amateur qui écrit du python pour un projet de recherche dans mon université. J'ai besoin que mon code soit très lisible pour tous ceux qui pourraient travailler sur ce projet après moi, et en tant que tel, j'essaie de suivre le PEP 8. J'ai cependant rencontré un conflit de règles. Les lignes incriminées sont une définition de dictionnaire après une longue chaîne de boucles for et d'instructions if. Le problème est que, selon la convention, aucune ligne ne doit comporter plus de 79 caractères, alors que les continuations de lignes devraient être indentées de leur point de départ. Je vois trois options de ce qui pourrait logiquement être fait, mais je ne suis pas sûr de ce qui est le mieux.Style de code Pythonic

option 1: laisser des lignes offenser trop longtemps

def getIndexedData(directory):             | 
    ...                  | 
    ...                  | 
    ...                  | 
         # construct dictionary of images with peak locations | 
         peaks[image] = {          | 
          'Xpixel': [float(x) for x in step[17][10][0].text.s|plit(' ')], 
          'Ypixel': [float(x) for x in step[17][10][1].text.s|plit(' ')]} 
    return peaks                | 

option 2: désindentation lignes continues

def getIndexedData(directory):             | 
    ...                  | 
    ...                  | 
    ...                  | 
         # construct dictionary of images with peak locations | 
         peaks[image] = {          | 
       'Xpixel': [float(x) for x in step[17][10][0].text.split(' ')], | 
       'Ypixel': [float(x) for x in step[17][10][1].text.split(' ')]} | 
    return peaks                | 

Option 3: définitions fendus quelque part (pas sûr où)

def getIndexedData(directory):             | 
    ...                  | 
    ...                  | 
    ...                  | 
         # construct dictionary of images with peak locations | 
         peaks[image] = {          | 
          'Xpixel':           | 
          [float(x) for x in step[17][10][0].text.split(' ')],| 
          'Ypixel':           | 
          [float(x) for x in step[17][10][1].text.split(' ')]}| 
    return peaks                | 

Je suis également ouvert à toute autre suggestion :)

Merci,

~ Aaron

+8

Il existe un échange de pile de révision de code que vous pouvez publier au lieu d'ici. – BlackVegetable

+5

La meilleure option peut très bien être "4: refactor, donc vous n'avez pas autant de niveaux d'indentation". – geoffspear

+1

Si je me souviens bien, PEP 8 suggère 120 caractères. 80 est très très strict, certains diraient obsolètes. Quant à votre question - j'irais avec la deuxième option - mais mon opinion est aussi bonne que n'importe laquelle. Juste aller avec ce que vous ressentez le mieux. Cela ne va certainement pas rendre votre code illisible. En second lieu, rappelez-vous que PEP8 est juste des directives - parfois vous avez des exceptions ... – alfasin

Répondre

2

Quelques extraits relevent de PEP 8 avec mes italiques ajoutés.

Un guide de style concerne la cohérence. La cohérence avec ce guide de style est importante. La cohérence au sein d'un projet est plus importante. La cohérence au sein d'un module ou d'une fonction est la plus importante.

Mais le plus important: savoir quand est incompatible - parfois le guide de style ne fonctionne tout simplement pas applicable. En cas de doute, utilisez votre meilleur jugement. Regardez d'autres exemples et décidez ce qui vous semble le mieux. Et ne hésitez pas à demander!

... qu'il est acceptable d'augmenter la longueur de la ligne nominale de 80 à 100 caractères ( augmentant efficacement la longueur maximale 99 caractères ), à condition que les observations et docstrings sont encore enveloppés à 72 caractères.

+0

Merci à tous pour vos commentaires et suggestions. Je vais certainement essayer quelques-unes de vos suggestions pour essayer de rendre la génération dict plus concise, mais pour le moment, le code sera probablement la première option que j'ai décrite. – Aaron

2

Les fonctions sont meilleures lorsqu'elles sont courtes et douces. J'entends par là qu'ils devraient avoir, si possible, un objectif très clairement défini et simple. Si une fonction a plusieurs niveaux d'indentation, c'est un signal que la fonction essaie d'en faire trop. Une partie de celui-ci peut probablement être refactorisée comme une fonction à part entière.

Un des avantages des "petites" fonctions est qu'elles facilitent la compréhension du code. Cela facilite également le test unitaire du code. Et enfin, il permet de garder le code sous la limite de 79 colonnes PEP8.

Cependant, une autre astuce que vous pouvez utiliser pour garder le code dans la limite de 79 colonne est d'utiliser des variables temporaires:

def getIndexedData(directory):             
    ...                   
    ...                   
    ...                   
         # construct dictionary of images with peak locations 
         texts = [text.split(' ') for text in step[17][10][:2]] 
         x, y = [map(float, text) for text in texts] 
         peaks[image] = {'Xpixel': x, 'Ypixel': y} 
    return peaks 
+0

wouldnt «textes» plus de sens comme un générateur de sorte que vous ne l'itérer qu'une seule fois? (+1 tout de même) –

+0

@JoranBeasley: Je doute que cela fasse une grande différence. Les générateurs font un bon travail pour réduire la consommation de mémoire, mais je ne pense pas qu'ils font beaucoup pour la performance ici (et peuvent même ralentir les choses). –

+0

dépend de la taille de la liste, je pense ... mais vous êtes ici, il serait certainement pas aider ... je n'ai pas remarqué que c'était seulement 2 éléments de long ... –

0

Essayez de réduire le nombre de boucles imbriquées pour-et si déclarations. Utilisez des fonctions, des générateurs ou des filtres pour y parvenir. Si vous montrez plus de votre code, nous pouvons vous aider. Vous pouvez également diviser la liste de génération à une ligne distincte:

xpixel = step[17][10][0].text.split(' ') 
ypixel = step[17][10][1].text.split(' ') 
peaks[image] = { 
    'Xpixel': map(float, xpixel), 
    'Ypixel': map(float, ypixel), 
} 

Vous pouvez également écrire une fonction de conversion:

def str_to_floats(text): 
    return [float(x) for x in text.split()] 

... 

peaks[image] = { 
    'Xpixel': str_to_floats(step[17][10][0].text), 
    'Ypixel': str_to_floats(step[17][10][1].text), 
} 

btw. step[17][10][0].text me semble étrange. De vos exemples, seule l'option 1 semble lisible pour moi.

+0

L'étape [...] provient d'un objet eTree provenant d'un fichier .xml analysé de plusieurs centaines de mégaoctets. Il peut y avoir un moyen plus efficace d'explorer la structure de données, mais cela semble fonctionner relativement vite et faire le travail. – Aaron