Maison >développement back-end >Tutoriel Python >Résumé de quelques conseils pour la programmation avancée en Python
Cet article présente principalement certaines compétences avancées de programmation en Python, y compris des points de connaissances avancés importants tels que les tuteurs et les décorateurs. Ce sont toutes des compétences de base nécessaires pour un apprentissage approfondi du développement Python.
Texte :
Cet article présente quelques structures de conception Python avancées et comment les utiliser. Dans le travail quotidien, vous pouvez choisir la structure de données appropriée en fonction de vos besoins, tels que les exigences de recherche rapide, les exigences de cohérence des données ou les exigences d'index. Vous pouvez également combiner diverses structures de données de manière appropriée, générant ainsi une logique et une simplicité. pour comprendre le modèle de données. Les structures de données de Python sont syntaxiquement très intuitives et fournissent un grand nombre d'opérations facultatives. Ce guide tente de rassembler la plupart des connaissances sur la structure de données couramment utilisées et de fournir une discussion sur leur meilleure utilisation.
Compréhensions
Si vous utilisez Python depuis longtemps, vous devriez au moins avoir entendu parler des compréhensions de listes. C'est une façon de mettre la boucle for, ifexpression et l'instruction d'affectation dans une seule instruction. En d’autres termes, vous pouvez mapper ou filtrer une liste via une expression.
Une compréhension de liste contient les parties suivantes :
Une séquence d'entrée
Une variable représentant les membres de la séquence d'entrée
Une expression d'assertion facultative
Une expression de sortie qui transforme les membres de la séquence d'entrée qui satisfont l'expression d'assertion en membres de la liste de sortie Formule
Par exemple, nous devons générer une nouvelle séquence à partir d'une liste d'entrée en mettant au carré tous les entiers supérieurs à 0. Vous pourriez écrire :
num = [1, 4, -5, 10, -7, 2, 3, -1] filtered_and_squared = [] for number in num: if number > 0: filtered_and_squared.append(number ** 2) print filtered_and_squared # [1, 16, 100, 4, 9]
Très simple, non ? Mais ce serait 4 lignes de code, deux niveaux d'imbrication et une opération d'ajout totalement inutile. Si vous utilisez les fonctions de filtre, lambda et map, le code peut être grandement simplifié :
num = [1, 4, -5, 10, -7, 2, 3, -1] filtered_and_squared = map(lambda x: x ** 2, filter(lambda x: x > 0, num)) print filtered_and_squared # [1, 16, 100, 4, 9]
Eh bien, de cette façon, le code s'étendra dans le sens horizontal. Alors peut-on continuer à simplifier le code ? La dérivation de liste peut nous donner la réponse :
num = [1, 4, -5, 10, -7, 2, 3, -1] filtered_and_squared = [ x**2 for x in num if x > 0] print filtered_and_squared # [1, 16, 100, 4, 9]
L'itérateur parcourt chaque membre de la séquence d'entrée num x
Le L'assertion détermine si chaque membre est supérieur à zéro
Si le membre est supérieur à zéro, il est donné à l'expression de sortie et devient membre de la liste de sortie après avoir été mis au carré.
La compréhension de liste est encapsulée dans une liste, elle génère donc évidemment une nouvelle liste instantanément. Il n'y a qu'un appel de fonction de type et aucun appel implicite à la fonction lambda. La compréhension de liste utilise un itérateur régulier, une expression et une expression if pour contrôler les paramètres facultatifs.
D'un autre côté, la compréhension de la liste peut également avoir des effets négatifs, c'est-à-dire que la liste entière doit être chargée dans la mémoire en même temps. Ce n'est pas un problème pour l'exemple donné ci-dessus, même après l'avoir été. élargi plusieurs fois. Rien de tout cela n’est un problème. Mais la limite sera toujours atteinte et la mémoire sera toujours utilisée.
Compte tenu des problèmes ci-dessus, Generator (Générateur) peut très bien le résoudre. L'expression génératrice ne charge pas la liste entière en mémoire en une seule fois, mais génère un objecteur générateur, de sorte qu'un seul élément de liste est chargé à la fois. Les expressions génératrices ont presque la même structure syntaxique que les compréhensions de liste. La différence est que les expressions génératrices sont entourées de parenthèses au lieu de crochets :
num = [1, 4, -5, 10, -7, 2, 3, -1] filtered_and_squared = ( x**2 for x in num if x > 0 ) print filtered_and_squared # <generator object <genexpr> at 0x00583E18> for item in filtered_and_squared: print item # 1, 16, 100 4,9Sauf raisons particulières, vous devez toujours utiliser des expressions génératrices dans votre code. Mais à moins que vous n’ayez affaire à de très grandes listes, vous ne verrez pas de différence significative.
num = [1, 4, -5, 10, -7, 2, 3, -1] def square_generator(optional_parameter): return (x ** 2 for x in num if x > optional_parameter) print square_generator(0) # <generator object <genexpr> at 0x004E6418> # Option I for k in square_generator(0): print k # 1, 16, 100, 4, 9 # Option II g = list(square_generator(0)) print g # [1, 16, 100, 4, 9]
L'exemple suivant utilise la fonction zip() pour traiter des éléments dans deux ou plusieurs listes à la fois :
alist = ['a1', 'a2', 'a3'] blist = ['1', '2', '3'] for a, b in zip(alist, blist): print a, b # a1 1 # a2 2 # a3 3Exemple de parcours de répertoire
import os def tree(top): for path, names, fnames in os.walk(top): for fname in fnames: yield os.path.join(path, fname) for name in tree('C:\Users\XXX\Downloads\Test'): print nameDécorateurs
Les décorateurs nous fournissent un moyen d'ajouter des fonctions existantes ou une méthode valide d'une fonction d'une classe. Cela ressemble-t-il beaucoup au concept de programmation orientée aspect (Aspect-Oriented Programming) en Java ? Les deux sont simples et les décorateurs sont plus puissants. Par exemple, si vous souhaitez effectuer certaines opérations spéciales (telles que de la sécurité, du suivi, du verrouillage, etc.) aux points d'entrée et de sortie d'une fonction, vous pouvez utiliser des décorateurs.
Un décorateur est une fonction spéciale qui enveloppe une autre fonction : la fonction principale est appelée et sa valeur de retour est transmise au décorateur, qui renvoie ensuite une fonction de remplacement qui enveloppe la fonction principale, quelles autres parties du programme voir sera cette fonction wrapper.
def timethis(func): ''' Decorator that reports the execution time. ''' pass @timethis def countdown(n): while n > 0: n -= 1
好了,让我们回到刚才的例子。我们将用装饰器做一些更典型的操作:
import time from functools import wraps def timethis(func): ''' Decorator that reports the execution time. ''' @wraps(func) def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) end = time.time() print(func.name, end-start) return result return wrapper @timethis def countdown(n): while n > 0: n -= 1 countdown(100000) # ('countdown', 0.006999969482421875)
当你写下如下代码时:
@timethis def countdown(n):
意味着你分开执行了以下步骤:
def countdown(n): ... countdown = timethis(countdown)
装饰器函数中的代码创建了一个新的函数(正如此例中的wrapper函数),它用 *args 和 **kwargs 接收任意的输入参数,并且在此函数内调用原函数并且返回其结果。你可以根据自己的需要放置任何额外的代码(例如本例中的计时操作),新创建的包装函数将作为结果返回并取代原函数。
@decorator def function(): print("inside function")
当编译器查看以上代码时,function()函数将会被编译,并且函数返回对象将会被传给装饰器代码,装饰器将会在做完相关操作之后用一个新的函数对象代替原函数。
装饰器代码是什么样的?大部分的例子都是将装饰器定义为函数,而我发觉将装饰器定义成类更容易理解其功能,并且这样更能发挥装饰器机制的威力。
对装饰器的类实现唯一要求是它必须能如函数一般使用,也就是说它必须是可调用的。所以,如果想这么做这个类必须实现call方法。
这样的装饰器应该用来做些什么?它可以做任何事,但通常它用在当你想在一些特殊的地方使用原函数时,但这不是必须的,例如:
class decorator(object): def init(self, f): print("inside decorator.init()") f() # Prove that function definition has completed def call(self): print("inside decorator.call()") @decorator def function(): print("inside function()") print("Finished decorating function()") function() # inside decorator.init() # inside function() # Finished decorating function() # inside decorator.call()
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!