Comment écrire du code Python efficace

巴扎黑
Libérer: 2017-09-09 11:38:38
original
1375 Les gens l'ont consulté

Cet article présente et explique principalement comment écrire du code Python efficace et élégant. Les amis qui en ont besoin peuvent s'y référer

Une partie de cet article est extraite du livre : "Effective Python" & "Python3 Cookbook". ", mais des modifications ont également été apportées et la propre compréhension et application des meilleures pratiques par l'auteur a été ajoutée.

Le texte intégral compte environ 9956 mots et sa lecture peut prendre 24 minutes.

Coupe de liste Pythonic

list[start:end:step]

Si vous commencez à couper depuis le début de la liste, ignorez le 0 dans le bit de départ, tel comme list[:4]

Si vous coupez jusqu'à la fin de la liste, ignorez le 0 dans le bit de fin. Par exemple, list[3:]

Lorsque vous coupez la liste, il y aura. ne posera aucun problème même si l'index de début ou de fin franchit la limite

Le découpage de liste ne modifie pas la liste d'origine. Lorsque les index sont tous laissés vides, une copie de la liste originale sera générée

Compréhensions de liste

Utilisez les compréhensions de liste pour remplacer map et filter

N'utilisez pas de compréhensions de listes contenant plus de deux expressions

Lorsqu'il y a beaucoup de données, Les compréhensions de liste peuvent Cela consomme beaucoup de mémoire. À l'heure actuelle, il est recommandé d'utiliser l'expression génératrice

itération

lorsque vous avez besoin d'obtenir le. index, utilisez enumerate

enumerateVous pouvez accepter le deuxième paramètre comme valeur ajoutée à index lors de l'itération

Utilisez zip pour parcourir deux itérateurs en même temps

zipRenvoie un tuple lors du parcours

À propos de for et whileelse blocs après la boucle

La boucle appellera le code dans après qu'il se termine normalementelse

Si vous utilisez break pour casser hors de la boucle, else

ne sera pas exécuté Lorsque la séquence à parcourir est vide, exécutez immédiatement else

Itération inverse.

Pour les séquences ordinaires (listes), nous pouvons passer la fonction intégrée La fonction reversed() effectue une itération inverse :

De plus, vous pouvez également effectuez une itération inverse sur la classe en implémentant la méthode __reversed__ dans la classe :

try/except/else/finally

Si aucune exception ne se produit dans try, le code dans else sera appelé

else dans finally Avant d'exécuter

finira par exécuter finally, où vous pourrez nettoyer la fonction

utilise un décorateur

Le décorateur permet de modifier le code de la fonction d'origine sans le changer Modifier une fonction existante. Un scénario courant consiste à ajouter une phrase de débogage ou à ajouter une logsurveillance

à une fonction existante. Par exemple :

De plus, vous pouvez. écrivez aussi Le décorateur qui reçoit les paramètres est en fait une fonction imbriquée dans la couche externe du décorateur d'origine :

Mais il y a un problème lors de l'utilisation du décorateur comme ci-dessus :

Autrement dit, la fonction d'origine a été remplacée par la fonction new_fun dans le décorateur. Appeler une fonction décorée équivaut à appeler une nouvelle fonction. Lors de l'affichage des paramètres, des commentaires et même des noms de fonction de la fonction d'origine, vous ne pouvez voir que les informations relatives au décorateur. Afin de résoudre ce problème, nous pouvons utiliser la méthode

propre functools.wraps de Python.

functools.wraps est une méthode très hack. Elle peut être utilisée comme décorateur sur la fonction qui sera renvoyée à l'intérieur du décorateur. En d'autres termes, il s'agit d'un décorateur de décorateurs, et prend la fonction originale comme paramètre. Sa fonction est de conserver diverses informations de la fonction originale, de sorte que lorsque nous visualisons ultérieurement les informations de la fonction originale décorée, elles puissent rester exactement. identique à la fonction d'origine.

De plus, notre décorateur peut parfois faire plus d'une chose, auquel cas l'événement doit être séparé en tant que fonction supplémentaire. Mais comme elle ne peut concerner que le décorateur, une classe de décorateur peut être construite à ce stade. Le principe est très simple, l'essentiel est d'écrire la méthode __call__ dans la classe pour que la classe puisse être appelée comme une fonction.

Utiliser des générateurs

Envisagez d'utiliser des générateurs pour réécrire des fonctions qui renvoient directement des listes

Il y a plusieurs petits problèmes avec cette méthode :

Chaque fois qu'un résultat répondant aux conditions est obtenu, la méthode append doit être appelée. Mais en fait, nous ne nous concentrons pas du tout sur cette méthode, c'est juste un moyen pour nous d'atteindre notre objectif. En fait, nous avons seulement besoin de index

Le result retourné peut continuer à être optimisé.

Les données sont stockées dans result Si la quantité de données est importante, elles occuperont plus de mémoire

Par conséquent, il est préférable d'utiliser le générateur generator. Un générateur est une fonction qui utilise une expression yield Lorsque le générateur est appelé, il ne s'exécutera pas réellement, mais renverra un itérateur à chaque fois que la fonction next intégrée est appelée sur l'itérateur. Le générateur passe à l'expression yield suivante :

Après avoir obtenu un générateur, vous pouvez le parcourir normalement :

Si vous avez encore besoin d'une liste, vous pouvez utiliser le résultat de l'appel de fonction comme paramètre puis appeler la listméthode

Objet itérable

Il convient de noter que les itérateurs ordinaires ne peuvent itérer que pendant un tour et que les appels répétés après un tour ne sont pas valides. La façon de résoudre ce problème est que vous pouvez définir une classe de conteneur itérable : Pas de problème :

Mais il faut noter qu'il ne s'agit que d'un itérateur qui implémente la méthode

et ne peut être itéré que dans la boucle

 ; si vous souhaitez passer Pour l'itération de la méthode, vous devez utiliser la méthode

 :

__iter__fornextiterUtiliser des paramètres de position

Parfois, le nombre de paramètres reçus par la méthode peut ne pas être certain, comme par exemple Définir une méthode de sommation qui doit recevoir au moins deux paramètres :

Pour ce genre de fonction qui n'a pas forcément un certain nombre de paramètres et ne se soucie pas de l'ordre dans lequel les paramètres sont passés, il faut utiliser les paramètres positionnels

:

*args Cependant, il convient de noter que le paramètre de longueur variable

doit d'abord être converti en tuple

lorsqu'il est transmis à la fonction. Cela signifie que si vous passez un générateur en paramètre à une fonction, le générateur sera parcouru en premier et converti en tuple. Cela peut consommer beaucoup de mémoire :

argstupleUtiliser des arguments de mots-clés

Les arguments de mots-clés améliorent la lisibilité du code

Peut transmettre les paramètres de mots-clés fournir des valeurs par défaut pour les fonctions

pour faciliter l'expansion des paramètres de fonction

Définir des fonctions qui ne peuvent utiliser que des paramètres de mots-clés

De la manière ordinaire , lors de l'appel, il ne forcera pas l'utilisation des paramètres de mots-clés lorsque

Utilisez la méthode de forçage des paramètres de mots-clés dans

Python3

Utilisez la méthode de forçage des paramètres de mots clés dans

Python2

À propos des valeurs par défaut des paramètres

C'est un cliché :La valeur par défaut d'une fonction ne sera définie qu'une seule fois lorsque le programme chargera le module et lit la définition de la fonction

En d'autres termes, si une valeur dynamique est affecté à un paramètre (

Par exemple ou

), si d'autres paramètres sont affectés aux paramètres lors de l'appel ultérieur de la fonction, lorsque cette fonction sera à nouveau appelée dans le futur, le défini précédemment la valeur par défaut changera et deviendra la valeur attribuée lors du dernier appel Valeur :

.

Par conséquent, il est plus recommandé d'utiliser None comme paramètre par défaut, et d'attribuer la valeur après jugement dans la fonction :

Class__slots__

Par défaut, Python utilise un dictionnaire pour enregistrer les attributs d'instance d'un objet. Cela nous permet d'ajouter dynamiquement de nouveaux attributs aux instances de classe au moment de l'exécution :

Cependant, ce dictionnaire gaspille de l'espace supplémentaire - souvent, nous ne le créerons pas avec autant d'attributs. Ainsi avec __slots__ vous pouvez dire à Python

de ne pas utiliser de dictionnaire mais une collection fixe pour allouer de l'espace.

__call__

En définissant la méthode __call__ dans une classe, les instances de la classe peuvent être appelées comme des fonctions ordinaires.

L'avantage d'implémenter cette méthode est que l'état peut être enregistré via les propriétés de la classe sans avoir à créer une fermeture ou une variable globale.

@classmethod & @staticmethod

@classmethod est très similaire à @staticmethod, mais leurs scénarios d'utilisation sont différents.

Les méthodes ordinaires de la classe utilisent toutes self comme premier paramètre, ce qui signifie que lorsqu'elles sont appelées via une instance, la portée de l'instance est transmise à la méthode

@classmethod ; Utiliser cls comme premier paramètre signifie passer dans la portée de la classe elle-même. Qu'il soit appelé via une classe ou une instance de classe, le premier paramètre transmis par défaut sera la classe elle-même

@staticmethodIl n'est pas nécessaire de transmettre des paramètres par défaut, semblable à une fonction ordinaire

Apprenons leurs scénarios d'utilisation à travers des exemples :

Supposons que nous devions créer une classe nommée Date pour stocker trois données année/mois/jour

Le code ci-dessus crée la classe Date, qui définit l'attribut day/month/year lors de l'initialisation, et définit un property à getter, qui peut être instancié via timeObtenir l'heure stockée :

Mais que se passe-t-il si nous voulons changer la façon dont les propriétés sont transmises ? Après tout, c'est embêtant de devoir passer les trois attributs année/mois/jour lors de l'initialisation. Pouvez-vous trouver un moyen de créer une instance de 2016-11-09 en passant une chaîne comme Date sans modifier l'interface et les méthodes existantes ?

Vous pourriez penser à une méthode comme celle-ci :

Mais ce n'est pas suffisant :

Écrivez une méthode supplémentaire en dehors de la classe, each Cette fois, vous devez formater puis récupérer les paramètres

Cette méthode est uniquement liée à la Date classe

ne résout pas le problème du trop grand nombre de paramètres passés dans

Vous pouvez l'utiliser à ce moment @classmethod, créer une nouvelle chaîne de format à l'intérieur de la classe et renvoyer la méthode de l'instance de classe :

De cette façon, nous peut l'appeler via la classe Date La méthode from_string crée une instance et n'envahit ni ne modifie l'ancienne méthode d'instanciation :

Avantages :

Dans @classmethod, vous pouvez transmettre clsParamètres, obtenez la même commodité que lors de l'appel de classes en externe

Vous pouvez y encapsuler davantage la méthode pour améliorer la réutilisabilité

Plus conforme à programmation orientée objet

Et @staticmethod, parce qu'elle est similaire à une fonction ordinaire, vous pouvez mettre la méthode d'assistance

liée à cette classe comme @staticmethod dans la classe, puis appelez cette méthode directement via la classe.

Après avoir placé les fonctions de classe auxiliaires liées à la date en tant que méthodes @staticmethod au sein de la classe Date, ces méthodes peuvent être appelées via la classe :

Créer un gestionnaire de contexte

Gestionnaire de contexte, l'introduction populaire est la suivante : avant l'exécution du bloc de code, le travail de préparation est effectué en premier après l'exécution du bloc de code, la finition ; le travail est terminé. Travail de traitement. L'instruction with apparaît souvent avec le gestionnaire de contexte. Les scénarios classiques incluent :

.

Grâce à l'instruction with, le code termine l'opération d'ouverture du fichier et ferme automatiquement le fichier lorsque l'appel se termine ou qu'une exception se produit pendant la lecture, c'est-à-dire le traitement après la lecture et l'écriture du fichier est terminée. Si vous ne passez pas le gestionnaire de contexte, le code sera comme ceci :

Ce n'est pas plus encombrant ? Ainsi, l'avantage d'utiliser le gestionnaire de contexte est qu'il nous aide automatiquement à gérer le travail lorsque le bloc de code démarre et termine son exécution en appelant nos rappels prédéfinis. Grâce aux méthodes __enter__ et __exit__ de la classe personnalisée, nous pouvons personnaliser un gestionnaire de contexte.

peut alors être appelé comme ceci :

Lors de l'appel :

Le with L'instruction stocke d'abord temporairement la méthode ReadFile __exit__

de la classe

, puis appelle la méthode ReadFile __enter__ de la classe

__enter__with pour ouvrir le fichier et stocke le résultat Renvoyé à l'instruction

file_read le résultat de l'étape précédente est passé au paramètre

with opère sur le paramètre file_read au sein du

et lit chaque ligne

withUne fois la lecture terminée, l'instruction __exit__ appelle la méthode

précédemment stockée

__exit__

pour fermer le fichier

__exit__Il convient de noter que dans la méthode True Inside, nous fermons le fichier, mais renvoyons with à la fin, donc l'erreur ne sera pas générée par l'instruction with. Sinon, l'instruction

générera une erreur correspondante.

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!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal