79 votes

Pièges communs en Python

Double Possible:
Python 2.x gotcha et des mines

Aujourd'hui, j'ai été mordu à nouveau par mutable arguments par défaut après de nombreuses années. J'ai l'habitude de ne pas utiliser mutable arguments par défaut, sauf si nécessaire, mais je pense qu'avec le temps j'ai oublié à ce sujet. Aujourd'hui, dans l'application, j'ai ajouté tocElements=[] dans un PDF fonction de génération de la liste d'arguments et d'aujourd'hui "Table des Matières" est plus longue et plus après chaque invocation de "générer un fichier pdf". :)

Que dois-je ajouter à ma liste de choses à éviter?

  • Toujours importer les modules de la même façon, par exemple, from y import x et import x sont considérés comme différents modules.

  • Ne pas utiliser de gamme à la place de listes, car range() deviendra un itérateur de toute façon, le suivant ne fonctionne pas:

    myIndexList = [0, 1, 3]
    isListSorted = myIndexList == range(3)  # will fail in 3.0
    isListSorted = myIndexList == list(range(3))  # will not
    

    La même chose peut être à tort, fait avec xrange:

    myIndexList == xrange(3)
    
  • Attention la capture de plusieurs types d'exceptions:

    try:
        raise KeyError("hmm bug")
    except KeyError, TypeError:
        print TypeError
    

    Ce imprime "hmm bug", si ce n'est pas un bug; il semble que nous sommes d'intercepter les exceptions de deux types, mais au lieu de cela nous sommes attraper KeyError seulement comme variable TypeError, utilisez ceci à la place:

    try:
        raise KeyError("hmm bug")
    except (KeyError, TypeError):
        print TypeError
    

73voto

e-satis Points 146299

Ne pas utiliser les index de boucle sur une séquence

Ne pas :

for i in range(len(tab)) :
    print tab[i]

Faire :

for elem in tab :
    print elem

Pour qui permettra d'automatiser les plus itération opérations pour vous.

Utiliser enumerate si vous avez vraiment besoin à la fois de l'indice et de l'élément.

for i, elem in enumerate(tab):
     print i, elem

Être prudent lors de l'utilisation de "==" pour vérifier contre Vrai ou Faux

if (var == True) :
    # this will execute if var is True or 1, 1.0, 1L

if (var != True) :
    # this will execute if var is neither True nor 1

if (var == False) :
    # this will execute if var is False or 0 (or 0.0, 0L, 0j)

if (var == None) :
    # only execute if var is None

if var :
    # execute if var is a non-empty string/list/dictionary/tuple, non-0, etc

if not var :
    # execute if var is "", {}, [], (), 0, None, etc.

if var is True :
    # only execute if var is boolean True, not 1

if var is False :
    # only execute if var is boolean False, not 0

if var is None :
    # same as var == None

Ne pas cocher si vous pouvez, il suffit de faire et de gérer l'erreur

Pythoneux l'habitude de dire "Il est plus facile de demander pardon que demander la permission".

Ne pas :

if os.path.isfile(file_path) :
    file = open(file_path)
else :
    # do something

Faire :

try :
    file =  open(file_path)
except OSError as e:
    # do something

Ou encore mieux avec python 2.6 / 3:

with open(file_path) as file :

C'est beaucoup mieux, parce que c'est beaucoup plus generical. Vous pouvez appliquer "try / except" pour presque rien. Vous n'avez pas besoin de se soucier de quoi faire pour l'empêcher, juste au sujet de l'erreur que vous risquez.

Ne cochez pas contre le type

Python est dynamiquement typé, donc la vérification de type vous fait perdre de la souplesse. Au lieu de cela, utiliser le duck-typing par le comportement du contrôle. E. G, vous vous attendez à une chaîne de caractères dans une fonction, puis de les utiliser str() pour convertir n'importe quel objet dans une chaîne de caractères. Vous vous attendez à une liste, utilisez la liste() pour convertir n'importe quel itérable dans une liste.

Ne pas :

def foo(name) :
    if isinstance(name, str) :
        print name.lower()

def bar(listing) :
    if isinstance(listing, list) :
        listing.extend((1, 2, 3))
        return ", ".join(listing)

Faire :

def foo(name) :
    print str(name).lower()

def bar(listing) :
    l = list(listing)
    l.extend((1, 2, 3))
    return ", ".join(l)

À l'aide de la dernière manière, foo va accepter n'importe quel objet. Barre d'accepter des chaînes, tuples, les décors, les listes et bien plus encore. Pas cher SEC :-)

Ne mélangez pas les espaces et tabulations

Il suffit de ne pas. Vous avez envie de pleurer.

L'utilisation de l'objet en tant que premier parent

C'est délicat, mais il va vous mordre que votre programme se développe. Il y a des vieilles et des nouvelles classes en Python 2.x. Les anciens sont, ainsi, le vieux. Il leur manque quelques fonctionnalités, et peut avoir maladroit comportement avec l'héritage. Pour être utilisable, tout de votre classe doit être de la "nouveau style". Pour ce faire, la faire hériter de "l'objet" :

Ne pas :

class Father :
    pass

class Child(Father) :
    pass

Faire :

class Father(object) :
    pass


class Child(Father) :
    pass

En Python 3.x toutes les classes sont nouveau style de sorte que vous n'avez pas besoin de le faire.

Ne pas initialiser les attributs de classe à l'extérieur de l' __init__ méthode

Les personnes en provenance d'autres langues trouver tentant parce que ce que vous faites le travail en Java ou en PHP. Vous écrivez le nom de la classe, puis la liste de vos attributs et de leur donner une valeur par défaut. Il semble fonctionner en Python, cependant, cela ne fonctionne pas de la façon dont vous pensez.

Ce qui de configuration des attributs de classe (statique attributs), lorsque vous essayez d'obtenir les attributs de l'objet, il vous donne sa valeur, sauf si elle est vide. Dans ce cas, il sera de retour les attributs de classe.

Il implique deux grands dangers :

  • Si l'attribut de classe est modifiée, la valeur initiale est modifiée.
  • Si vous définissez un objet mutable comme valeur par défaut, vous obtiendrez le même objet partagé entre les instances.

Ne pas (sauf si vous voulez statique) :

class Car(object):
    color = "red"
    wheels = [wheel(), Wheel(), Wheel(), Wheel()]

Faire :

class Car(object):
    def __init__(self):
        self.color = "red"
        self.wheels = [wheel(), Wheel(), Wheel(), Wheel()]

39voto

Jorisslob Points 31

Lorsque vous avez besoin d’une population de tableaux, vous pourriez être tenté de taper quelque chose comme ceci :

Et bien sûr, il vous donnera ce que vous attendez quand vous le regardez

Mais ne vous attendez pas les éléments de votre population d’être des objets distincts :

Sauf si c’est ce dont vous avez besoin...

Il est à noter une solution de contournement :

28voto

S.Lott Points 207588

Langage Python Pièges, des choses qui ne parviennent pas à très obscure façons

  • À l'aide mutable arguments par défaut.

  • Les zéros à gauche signifie octal. 09 est un très obscure erreur de syntaxe de Python 2.x

  • Faute de méthode de remplacement des noms dans une super-classe ou sous-classe. La superclasse faute d'orthographe erreur est pire, parce qu'aucune des sous-classes de la remplacer correctement.

Python Conception De Pièges

  • Passer du temps sur l'introspection (par exemple, en essayant de déterminer automatiquement les types ou superclasse d'identité ou d'autres trucs). Tout d'abord, il est évident à la lecture de la source. Plus important encore, le temps passé sur bizarre Python introspection indique généralement un échec fondamental de saisir le polymorphisme. 80% de l'Python introspection questions sur SI sont l'incapacité à obtenir le Polymorphisme.

  • Passer du temps sur le code de golf. Juste parce que votre modèle mental de votre demande est de quatre mots-clés ("faire", "quoi", "I", "moyenne"), ne signifie pas que vous devez construire un hyper-complexe introspective décorateur-pilotée-cadre pour le faire. Python vous permet de vous tenir au SEC, à un niveau qui est de la bêtise. Le reste de l'Python introspection questions sur les tentatives AFIN de réduire les problèmes complexes de code de golf des exercices.

  • Monkeypatching.

  • L'échec de lire par le biais de la bibliothèque standard, et de réinventer la roue.

  • L'amalgame entre la interactive type-que-vous allez Python avec un programme approprié. Pendant que vous êtes en train de saisir de manière interactive, vous pouvez perdre la trace d'une variable et utiliser globals(). Aussi, pendant que vous êtes en train de saisir, presque tout est global. En bon programmes, vous ne serez jamais "perdre" une variable, et rien ne sera mondiale.

26voto

Will Harris Points 17002

Mutation d'un argument par défaut:

 def foo(bar=[]):
    bar.append('baz')
    return bar
 

La valeur par défaut n'est évaluée qu'une fois, et pas à chaque appel de la fonction. Les appels répétés à foo() renverraient ['baz'] , ['baz', 'baz'] , ['baz', 'baz', 'baz'] , ...

Si vous voulez changer de barre, faites quelque chose comme ça:

 def foo(bar=None):
    if bar is None:
        bar = []

    bar.append('baz')
    return bar
 

Ou, si vous souhaitez que les arguments soient définitifs:

 def foo(bar=[]):
    not_bar = bar[:]

    not_bar.append('baz')
    return not_bar
 

22voto

Jochen Walter Points 834

Je ne sais pas s’il s’agit d’une erreur courante, mais bien que python ne dispose pas d’opérateurs d’incrémentation et de décrémentation, les doubles signes sont autorisés.

 ++i
 

et

 --i
 

est un code syntaxiquement correct, mais ne fait rien.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X