Double Possible:
Python 2.x gotcha et des minesAujourd'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
etimport 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
- Les gotchas et les mines de Python 2.x (5 réponses )
Réponses
Trop de publicités?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()]
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 :
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.xFaute 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.
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