Antimodèles dans la programmation Python
Cet article rassemble des problèmes irréguliers mais parfois subtils que j'ai vus dans le code écrit par des développeurs Python novices. Le but de cet article est d'aider les développeurs novices à dépasser le stade de l'écriture de code Python laid. Afin de prendre en compte le public cible, cet article a apporté quelques simplifications (par exemple, lors de la discussion sur les itérateurs, les générateurs et le puissant outil d'itération itertools sont ignorés).
Pour les développeurs débutants, il y a toujours des raisons d'utiliser des anti-modèles et j'ai essayé de donner ces raisons dans la mesure du possible. Mais généralement, ces anti-modèles aboutissent à un code moins lisible, plus sujet aux bugs et non conforme au style de codage de Python. Si vous recherchez du matériel d'introduction plus pertinent, je vous recommande vivement The Tutoriel Python ou Plongez dans Python.
Itération
Utilisation de range
Les débutants en programmation Python aiment utiliser range pour implémenter une itération simple et obtenir des itérations dans la plage de longueur de l'itérateur Chaque élément du conteneur :
for i in range(len(alist)): print alist[i]
Il convient de rappeler que range n'est pas destiné à implémenter une simple itération de la séquence. Par rapport à celles définies avec des nombres, bien que la boucle for implémentée avec range semble très naturelle, elle est sujette à des bugs lorsqu'elle est utilisée dans une itération de séquence, et elle n'est pas aussi claire que la construction directe d'un itérateur :
for item in alist: print item
L'abus de range peut facilement provoquer des erreurs inattendues, généralement causées par les nouveaux programmeurs qui oublient que l'objet généré par range inclut le premier paramètre de range, à l'exclusion du second. , il est similaire à substring et à de nombreuses autres fonctions de ce type en Java. Les nouveaux programmeurs qui pensent que la fin de la séquence n'est pas dépassée créeront des bugs :
# 迭代整个序列错误的方法 alist = ['her', 'name', 'is', 'rio'] for i in range(0, len(alist) - 1): # 大小差一(Off by one)! print i, alist[i]
Raisons courantes d'utilisation inappropriée des plages :
1. Besoin d'utiliser l'index en boucle. Ce n'est pas une raison valable, vous pouvez utiliser ce qui suit au lieu d'utiliser l'index :
for index, value in enumerate(alist): print index, value
2. Vous devez parcourir deux boucles en même temps et utiliser le même index pour obtenir deux valeurs. Dans ce cas, zip peut être utilisé :
for word, number in zip(words, numbers): print word, number
3. Une partie de la séquence doit être itérée. Dans ce cas, cela peut être réalisé en itérant simplement sur la tranche de séquence. Veuillez ajouter les commentaires nécessaires pour indiquer le but :
for word in words[1:]: # 不包括第一个元素 print word
Il y a une exception : lorsque vous parcourez une grande séquence, le découpage est effectué. causes de fonctionnement Le coût est relativement important. Si la séquence ne comporte que 10 éléments, cela ne pose pas de problème ; mais s'il y a 10 millions d'éléments, ou si l'opération de découpage est effectuée dans une boucle interne sensible aux performances, la surcharge devient très importante. Dans ce cas, vous pouvez envisager d'utiliser xrange au lieu de range [1].
En plus d'être utilisé pour parcourir une séquence, une utilisation importante de range est lorsque vous souhaitez réellement générer une séquence de nombres plutôt que de générer un index :
# Print foo(x) for 0<=x<5 for x in range(5): print foo(x)
Utilisez correctement les compréhensions de liste
Si vous avez une boucle comme celle-ci :
# An ugly, slow way to build a list words = ['her', 'name', 'is', 'rio'] alist = [] for word in words: alist.append(foo(word))
Vous pouvez utiliser les compréhensions de listes pour réécrire :
words = ['her', 'name', 'is', 'rio'] alist = [foo(word) for word in words]
Pourquoi faire ça ? D'une part, vous évitez d'éventuelles erreurs causées par une initialisation correcte de la liste. D'autre part, écrire le code de cette façon lui donne un aspect propre et ordonné. Pour ceux qui ont une formation en programmation fonctionnelle, l'utilisation de la fonction map peut sembler plus familière, mais à mon avis, cette approche est moins pythonique.
Quelques autres raisons courantes de ne pas utiliser les compréhensions de listes :
1. À ce stade, vous pouvez imbriquer l'intégralité de l'analyse de liste ou utiliser des boucles sur plusieurs lignes dans l'analyse de liste :
words = ['her', 'name', 'is', 'rio'] letters = [] for word in words: for letter in word: letters.append(letter)
Utiliser l'analyse de liste :
words = ['her', 'name', 'is', 'rio'] letters = [letter for word in words for letter in word]
Remarque : Dans une compréhension de liste avec plusieurs boucles, les boucles sont dans le même ordre que si vous n'utilisiez pas de compréhension de liste.
2. Vous avez besoin d'un jugement conditionnel à l'intérieur de la boucle. Il vous suffit d'ajouter ce conditionnel à la compréhension de liste :
words = ['her', 'name', 'is', 'rio', '1', '2', '3'] alpha_words = [word for word in words if isalpha(word)]
Une bonne raison de ne pas utiliser les compréhensions de liste est que vous ne pouvez pas utiliser d'exceptions dans les compréhensions de liste. avec. Si certains éléments de l'itération peuvent provoquer des exceptions, vous devez transférer la gestion éventuelle des exceptions via des appels de fonction dans la compréhension de liste, ou ne pas utiliser du tout la compréhension de liste.
Défauts de performances
Vérification du contenu en temps linéaire
Syntaxiquement, vérifier si une liste ou un ensemble/dict contient un élément ne semble faire aucune différence en surface, mais en dessous la surface, c'est complètement différent. Si vous devez vérifier à plusieurs reprises si une certaine structure de données contient un élément, il est préférable d'utiliser un ensemble plutôt qu'une liste. (Si vous souhaitez associer une valeur à l'élément à vérifier, vous pouvez utiliser un dict ; cela permet également d'obtenir un temps de vérification constant.)
# 假设以list开始 lyrics_list = ['her', 'name', 'is', 'rio'] # 避免下面的写法 words = make_wordlist() # 假设返回许多要测试的单词 for word in words: if word in lyrics_list: # 线性检查时间 print word, "is in the lyrics" # 最好这么写 lyrics_set = set(lyrics_list) # 线性时间创建set words = make_wordlist() # 假设返回许多要测试的单词 for word in words: if word in lyrics_set: # 常数检查时间 print word, "is in the lyrics"
[Note du traducteur : Les éléments de set et les valeurs clés de dict en Python sont hachables, donc la complexité temporelle de la recherche est O(1). ]
Il ne faut pas oublier que la création d'un ensemble introduit une surcharge ponctuelle et que le processus de création prendra un temps linéaire même si la vérification des membres prend un temps constant. Donc si vous avez besoin de vérifier des membres dans une boucle, il est préférable de prendre le temps de créer d'abord l'ensemble, puisque vous ne devez le créer qu'une seule fois.
Fuite de variable
Boucle
De manière générale, en Python, la portée d'une variable est plus large que dans d'autres langages. être généreux. Par exemple : Le code suivant en Java ne sera pas compilé :
// Get the index of the lowest-indexed item in the array // that is > maxValue for(int i = 0; i < y.length; i++) { if (y[i] > maxValue) { break; } } // i在这里出现不合法:不存在i processArray(y, i);
Cependant, en Python, le même code s'exécutera toujours correctement et obtiendra les résultats attendus :
for idx, value in enumerate(y): if value > max_value: break processList(y, idx)
这段代码将会正常运行,除非子y为空的情况下,此时,循环永远不会执行,而且processList函数的调用将会抛出NameError异常,因为idx没有定义。如果你使用Pylint代码检查工具,将会警告:使用可能没有定义的变量idx。
解决办法永远是显然的,可以在循环之前设置idx为一些特殊的值,这样你就知道如果循环永远没有执行的时候你将要寻找什么。这种模式叫做哨兵模式。那么什么值可以用来作为哨兵呢?在C语言时代或者更早,当int统治编程世界的时候,对于需要返回一个期望的错误结果的函数来说为通用的模式为返回-1。例如,当你想要返回列表中某一元素的索引值:
def find_item(item, alist): # None比-1更加Python化 result = -1 for idx, other_item in enumerate(alist): if other_item == item: result = idx break return result
通常情况下,在Python里None是一个比较好的哨兵值,即使它不是一贯地被Python标准类型使用(例如:str.find [2])
外作用域
Python程序员新手经常喜欢把所有东西放到所谓的外作用域——python文件中不被代码块(例如函数或者类)包含的部分。外作用域相当于全局命名空间;为了这部分的讨论,你应该假设全局作用域的内容在单个Python文件的任何地方都是可以访问的。
对于定义整个模块都需要去访问的在文件顶部声明的常量,外作用域显得非常强大。给外作用域中的任何变量使用有特色的名字是明智的做法,例如,使用IN_ALL_CAPS 这个常量名。 这将不容易造成如下bug:
import sys # See the bug in the function declaration? def print_file(filenam): """Print every line of a file.""" with open(filename) as input_file: for line in input_file: print line.strip() if __name__ == "__main__": filename = sys.argv[1] print_file(filename)
如果你看的近一点,你将看到print_file函数的定义中用filenam命名参数名,但是函数体却引用的却是filename。然而,这个程序仍然可以运行得很好。为什么呢?在print_file函数里,当一个局部变量filename没有被找到时,下一步是在全局作用域中去寻找。由于print_file的调用在外作用域中(即使有缩进),这里声明的filename对于print_file函数是可见的。
那么如何避免这样的错误呢?首先,在外作用域中不是IN_ALL_CAPS这样的全局变量就不要设置任何值[3]。参数解析最好交给main函数,因此函数中任何内部变量不在外作用域中存活。
这也提醒人们关注全局关键字global。如果你只是读取全局变量的值,你就不需要全局关键字global。你只有在想要改变全局变量名引用的对象时有使用global关键字的必要。你可以在这里获取更多相关信息this discussion of the global keyword on Stack Overflow(http://stackoverflow.com/questions/4693120/use-of-global-keyword-in-python/4693170#4693170)。
代码风格
向PEP8致敬
PEP 8是Python代码的通用风格指南,你应该牢记在心并且尽可能去遵循它,尽管一些人有充分的理由不同意其中一些细小的风格,例如缩进的空格个数或使用空行。如果你不遵循PEP8,你应该有除“我只是不喜欢那样的风格”之外更好的理由。下边的风格指南都是从PEP8中摘取的,似乎是编程者经常需要牢记的。
测试是否为空
如果你要检查一个容器类型(例如:列表,词典,集合)是否为空,只需要简单测试它而不是使用类似检查len(x)>0这样的方法:
numbers = [-1, -2, -3] # This will be empty positive_numbers = [num for num in numbers if num > 0] if positive_numbers: # Do something awesome
如果你想在其他地方保存positive_numbers是否为空的结果,可以使用bool(positive_number)作为结果保存;bool用来判断if条件判断语句的真值。
测试是否为None
如前面所提到,None可以作为一个很好的哨兵值。那么如何检查它呢?
如果你明确的想要测试None,而不只是测试其他一些值为False的项(如空容器或者0),可以使用:
if x is not None: # Do something with x
如果你使用None作为哨兵,这也是Python风格所期望的模式,例如在你想要区分None和0的时候。
如果你只是测试变量是否为一些有用的值,一个简单的if模式通常就够用了:
if x: # Do something with x
例如:如果期望x是一个容器类型,但是x可能作另一个函数的返回结果值变为None,你应该立即考虑到这种情况。你需要留意是否改变了传给x的值,否则可能你认为True或0. 0是个有用的值,程序却不会按照你想要的方式执行。
译者注:
[1] 在Python2.x 中 range生成的是list对象,xrange生成的则是range对象;Python 3.x 废除了xrange,range生成的统一为range对象,用list工厂函数可以显式生成list;
[2] string.find(str)返回str在string中开始的索引值,如果不存在则返回-1;
[3] Ne définissez aucune valeur sur le nom de la variable locale dans la fonction dans la portée externe pour éviter une erreur lors de l'appel de la variable locale à l'intérieur de la fonction et de l'appel de la variable avec le même nom dans la portée externe.
Ce qui précède est le contenu des anti-modèles dans la programmation Python. Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois (www.php.cn) !

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

Video Face Swap
Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds











PHP est principalement la programmation procédurale, mais prend également en charge la programmation orientée objet (POO); Python prend en charge une variété de paradigmes, y compris la POO, la programmation fonctionnelle et procédurale. PHP convient au développement Web, et Python convient à une variété d'applications telles que l'analyse des données et l'apprentissage automatique.

PHP convient au développement Web et au prototypage rapide, et Python convient à la science des données et à l'apprentissage automatique. 1.Php est utilisé pour le développement Web dynamique, avec une syntaxe simple et adapté pour un développement rapide. 2. Python a une syntaxe concise, convient à plusieurs champs et a un écosystème de bibliothèque solide.

PHP est originaire en 1994 et a été développé par Rasmuslerdorf. Il a été utilisé à l'origine pour suivre les visiteurs du site Web et a progressivement évolué en un langage de script côté serveur et a été largement utilisé dans le développement Web. Python a été développé par Guidovan Rossum à la fin des années 1980 et a été publié pour la première fois en 1991. Il met l'accent sur la lisibilité et la simplicité du code, et convient à l'informatique scientifique, à l'analyse des données et à d'autres domaines.

Python convient plus aux débutants, avec une courbe d'apprentissage en douceur et une syntaxe concise; JavaScript convient au développement frontal, avec une courbe d'apprentissage abrupte et une syntaxe flexible. 1. La syntaxe Python est intuitive et adaptée à la science des données et au développement back-end. 2. JavaScript est flexible et largement utilisé dans la programmation frontale et côté serveur.

Pour exécuter le code Python dans le texte sublime, vous devez d'abord installer le plug-in Python, puis créer un fichier .py et écrire le code, et enfin appuyez sur Ctrl B pour exécuter le code, et la sortie sera affichée dans la console.

L'écriture de code dans Visual Studio Code (VSCODE) est simple et facile à utiliser. Installez simplement VScode, créez un projet, sélectionnez une langue, créez un fichier, écrivez du code, enregistrez-le et exécutez-le. Les avantages de VSCOD incluent la plate-forme multiplateuse, gratuite et open source, des fonctionnalités puissantes, des extensions riches et des poids légers et rapides.

VS Code peut être utilisé pour écrire Python et fournit de nombreuses fonctionnalités qui en font un outil idéal pour développer des applications Python. Il permet aux utilisateurs de: installer des extensions Python pour obtenir des fonctions telles que la réalisation du code, la mise en évidence de la syntaxe et le débogage. Utilisez le débogueur pour suivre le code étape par étape, trouver et corriger les erreurs. Intégrez Git pour le contrôle de version. Utilisez des outils de mise en forme de code pour maintenir la cohérence du code. Utilisez l'outil de liaison pour repérer les problèmes potentiels à l'avance.

L'exécution du code Python dans le bloc-notes nécessite l'installation du plug-in exécutable Python et du plug-in NPEXEC. Après avoir installé Python et ajouté un chemin à lui, configurez la commande "python" et le paramètre "{current_directory} {file_name}" dans le plug-in nppexec pour exécuter le code python via la touche de raccourci "F6" dans le bloc-notes.
