Python >> Tutoriel Python >  >> Python

Percevoir les paradigmes de programmation Python

Au début de chaque année, TIOBE annonce son langage de programmation de l'année. Lorsque son dernier rapport annuel sur l'indice TIOBE est sorti, je n'ai pas du tout été surpris de voir Python remporter à nouveau le titre, qui était basé sur la capture du plus grand nombre de points de classement des moteurs de recherche (en particulier sur Google, Bing, Yahoo, Wikipedia, Amazon, YouTube, et Baidu) en 2018.

Ajoutant du poids aux conclusions de TIOBE, plus tôt cette année, près de 90 000 développeurs ont participé à l'enquête annuelle des développeurs de Stack Overflow, qui est l'enquête la plus vaste et la plus complète auprès des personnes qui codent dans le monde. Le principal point à retenir des résultats de cette année était :

Depuis que j'ai commencé à programmer et à explorer différents langages, j'ai vu l'admiration pour Python monter en flèche. Depuis 2003, il a toujours été parmi les 10 langages de programmation les plus populaires. Comme l'indique le rapport de TIOBE :

Plusieurs raisons expliquent l'essor rapide, la floraison et la domination de Python dans plusieurs domaines, notamment le développement Web, l'informatique scientifique, les tests, la science des données, l'apprentissage automatique, etc. Les raisons incluent son code lisible et maintenable; prise en charge étendue des intégrations et bibliothèques tierces ; structure modulaire, dynamique et portable ; programmation flexible; facilité d'apprentissage et soutien; structures de données conviviales ; productivité et rapidité; et, le plus important, le soutien de la communauté. La diversité des applications de Python est le résultat de ses fonctionnalités combinées, qui lui donnent un avantage sur les autres langages.

Mais à mon avis, la simplicité relative de sa syntaxe et la flexibilité stupéfiante qu'elle offre aux développeurs venant de nombreux autres langages remportent le gâteau. Très peu de langages peuvent égaler la capacité de Python à se conformer au style de codage d'un développeur plutôt que de le forcer à coder d'une manière particulière. Python permet aux développeurs plus avancés d'utiliser le style qu'ils jugent le mieux adapté pour résoudre un problème particulier.

Lorsque vous travaillez avec Python, vous êtes comme un charmeur de serpent. Cela vous permet de tirer parti de la promesse de Python d'offrir un environnement non conforme aux développeurs pour coder dans le style le mieux adapté à une situation particulière et rendre le code plus lisible, testable et cohérent.

Paradigmes de programmation Python

Python prend en charge quatre principaux paradigmes de programmation :impératif, fonctionnel, procédural et orienté objet. Que vous soyez d'accord qu'ils sont valides ou même utiles, Python s'efforce de rendre les quatre disponibles et fonctionnels. Avant de plonger pour voir quel paradigme de programmation est le plus adapté à des cas d'utilisation spécifiques, c'est le bon moment pour les passer en revue rapidement.

Paradigme de programmation impératif

Le paradigme de la programmation impérative utilise le mode impératif du langage naturel pour exprimer des directions. Il exécute les commandes étape par étape, tout comme une série de commandes verbales. Suivant l'approche "comment résoudre", il apporte des modifications directes à l'état du programme ; c'est pourquoi on l'appelle aussi le modèle de programmation avec état. En utilisant le paradigme de la programmation impérative, vous pouvez écrire rapidement un code très simple mais élégant, et c'est très pratique pour les tâches qui impliquent la manipulation de données. En raison de sa stratégie d'exécution relativement plus lente et séquentielle, il ne peut pas être utilisé pour des calculs complexes ou parallèles.

Considérez cet exemple de tâche, où le but est de prendre une liste de caractères et de la concaténer pour former une chaîne. Une façon de le faire dans un style de programmation impératif serait quelque chose comme :

>>> sample_characters = ['p','y','t','h','o','n']
>>> sample_string = ''
>>> sample_string
''
>>> sample_string = sample_string + sample_characters[0]
>>> sample_string
'p'
>>> sample_string = sample_string + sample_characters[1]
>>> sample_string
'py'
>>> sample_string = sample_string + sample_characters[2]
>>> sample_string
'pyt'
>>> sample_string = sample_string + sample_characters[3]
>>> sample_string
'pyth'
>>> sample_string = sample_string + sample_characters[4]
>>> sample_string
'pytho'
>>> sample_string = sample_string + sample_characters[5]
>>> sample_string
'python'
>>>

Ici, la variable sample_string est également comme un état du programme qui est modifié après l'exécution de la série de commandes, et il peut être facilement extrait pour suivre la progression du programme. La même chose peut être faite en utilisant un pour boucle (également considérée comme programmation impérative) dans une version plus courte du code ci-dessus :

>>> sample_characters = ['p','y','t','h','o','n']
>>> sample_string = ''
>>> sample_string
>>> for c in sample_characters:
...    sample_string = sample_string + c
...    print(sample_string)
...
p
py
pyt
pyth
pytho
python
>>>

Paradigme de programmation fonctionnelle

Le paradigme de la programmation fonctionnelle traite le calcul du programme comme l'évaluation de fonctions mathématiques basées sur le calcul lambda. Le calcul lambda est un système formel en logique mathématique pour exprimer le calcul basé sur l'abstraction et l'application de fonctions utilisant la liaison et la substitution de variables. Il suit l'approche "quoi résoudre", c'est-à-dire qu'il exprime la logique sans décrire son flux de contrôle. Il est donc également classé comme modèle de programmation déclarative.

Le paradigme de la programmation fonctionnelle promeut les fonctions sans état, mais il est important de noter que l'implémentation de la programmation fonctionnelle par Python s'écarte de l'implémentation standard. On dit que Python est un impur langage fonctionnel car il est possible de maintenir l'état et de créer des effets secondaires si vous ne faites pas attention. Cela dit, la programmation fonctionnelle est pratique pour le traitement parallèle et est extrêmement efficace pour les tâches nécessitant une récursivité et une exécution simultanée.

>>> sample_characters = ['p','y','t','h','o','n']
>>> import functools
>>> sample_string = functools.reduce(lambda s,c: s + c, sample_characters)
>>> sample_string
'python'
>>>

En utilisant le même exemple, la manière fonctionnelle de concaténer une liste de caractères pour former une chaîne serait la même que ci-dessus. Étant donné que le calcul se déroule sur une seule ligne, il n'existe aucun moyen explicite d'obtenir l'état du programme avec sample_string et suivre la progression. La mise en œuvre de la programmation fonctionnelle de cet exemple est fascinante, car elle réduit les lignes de code et fait simplement son travail en une seule ligne, à l'exception de l'utilisation des functools module et le module réduire méthode. Les trois mots-clés—functools , réduire , et lambda —sont définis comme suit :

  • outils fonctionnels est un module pour les fonctions d'ordre supérieur et fournit des fonctions qui agissent sur ou renvoient d'autres fonctions. Cela encourage l'écriture de code réutilisable, car il est plus facile de répliquer des fonctions existantes avec certains arguments déjà passés et de créer une nouvelle version d'une fonction de manière bien documentée.
  • réduire est une méthode qui applique une fonction de deux arguments de manière cumulative aux éléments en séquence, de gauche à droite, pour réduire la séquence à une seule valeur. Par exemple :
    >>> sample_list = [1,2,3,4,5]
    >>> import functools
    >>> sum = functools.reduce(lambda x,y: x + y, sample_list)
    >>> sum
    15
    >>> ((((1+2)+3)+4)+5)
    15
    >>>
  • fonctions lambda sont de petites fonctions anonymisées (c'est-à-dire sans nom) qui peuvent prendre n'importe quel nombre d'arguments mais ne recracher qu'une seule valeur. Ils sont utiles lorsqu'ils sont utilisés comme argument pour une autre fonction ou résident à l'intérieur d'une autre fonction; par conséquent, ils ne sont destinés à être utilisés que pour une instance à la fois.

Paradigme de programmation procédurale

Le paradigme de programmation procédurale est un sous-type de programmation impérative dans lequel les instructions sont structurées en procédures (également appelées sous-routines ou fonctions). La composition du programme est plus un appel de procédure où les programmes peuvent résider quelque part dans l'univers et l'exécution est séquentielle, devenant ainsi un goulot d'étranglement pour l'utilisation des ressources. Comme le paradigme de la programmation impérative, la programmation procédurale suit le modèle avec état. Le paradigme de la programmation procédurale facilite la pratique d'une bonne conception de programme et permet de réutiliser les modules sous la forme de bibliothèques de code.

Cette forme de développement modularisé est un style de développement très ancien. Les différents modules d'un programme peuvent n'avoir aucune relation les uns avec les autres et peuvent être situés à différents endroits, mais le fait d'avoir une multitude de modules crée des difficultés pour de nombreux développeurs, car cela entraîne non seulement une duplication de la logique, mais également beaucoup de frais généraux en termes de trouver et de faire les bons appels. Notez que dans l'implémentation suivante, la méthode stringify pourrait être défini n'importe où dans l'univers et, pour faire son truc, ne nécessite que l'appel approprié avec les arguments souhaités.

>>> def stringify(characters):
...    string = ''
...    for c in characters:
...        string = string + c
...    return stringify
...
>>> sample_characters = ['p','y','t','h','o','n']
>>> stringify(sample_characters)
'python'
>>>

Paradigme de programmation orienté objet

Le paradigme de la programmation orientée objet considère les entités de base comme des objets dont l'instance peut contenir à la fois des données et les méthodes correspondantes pour modifier ces données. Les différents principes de la conception orientée objet aident à la réutilisation du code, au masquage des données, etc., mais c'est une bête complexe, et écrire la même logique dans une méthode orientée objet est délicat. Par exemple :

>>> class StringOps:
...    def __init__(self, characters):
...        self.characters = characters
...    def stringify(self):
...        self.string = ''.join(self.characters)
...
>>> sample_characters = ['p','y','t','h','o','n']
>>> sample_string = StringOps(sample_characters)
>>> sample_string.stringify()
>>> sample_string.string
'python'
>>>

Quel paradigme de programmation dois-je choisir ?

Il est important de noter qu'il n'y a pas de comparaison entre les différents types de paradigmes de programmation. Puisque le logiciel n'est rien d'autre que la représentation des connaissances, la réponse à la question :"Quelle est la meilleure façon de représenter mon problème ?" choisit un paradigme de programmation spécifique.

En termes simples, si votre problème implique une série de manipulations séquentielles simples, suivre le paradigme de la programmation impérative à l'ancienne serait le moins coûteux en termes de temps et d'efforts et vous donnerait les meilleurs résultats. Dans le cas de problèmes nécessitant des transformations mathématiques de valeurs, le filtrage d'informations, le mappage et les réductions, la programmation fonctionnelle avec calcul de programme en tant que fonctions mathématiques peut s'avérer utile. Si le problème est structuré comme un groupe d'objets interdépendants avec certains attributs qui peuvent changer avec le temps, en fonction de certaines conditions, la programmation orientée objet sera extrêmement utile. Bien sûr, une approche basée sur des règles ne fonctionnerait pas ici, car le choix du paradigme de programmation dépend également fortement du type de données à traiter, des besoins dynamiques du système et de divers autres éléments tels que l'évolutivité.

L'analyse des derniers mots à la mode de la technologie peut aider à identifier pourquoi certains paradigmes de programmation fonctionnent mieux que d'autres.

  • Apprentissage automatique utilise un mélange sain de programmation impérative et de programmation fonctionnelle avec une touche d'immuabilité. L'extraction et le prétraitement des caractéristiques sont mieux abordés de manière fonctionnelle, car ils nécessitent un traitement mathématique des données, car les mappages, les réductions et les filtrages peuvent pratiquement être effectués en parallèle sans trop dépendre des points de données les uns des autres. La formation des modèles d'apprentissage automatique est mieux abordée via la programmation impérative à l'ancienne, car l'optimisation de la valeur des fonctions (c'est-à-dire l'état du programme) doit être mise à jour à chaque itération et nécessite donc une exécution séquentielle à de nombreux points de l'algorithme. C'est plus rapide que la programmation fonctionnelle dans ce cas. Cela évite également de créer des copies de tout après chaque étape; à la place, il met simplement à jour les espaces réservés de la valeur précédente.
  • Apprentissage en profondeur peuvent être bien exécutés de manière fonctionnelle, car les modèles d'apprentissage en profondeur sont compositionnels. L'ensemble du processus optimise un ensemble de fonctions composites, les pondérations sont immuables et sans état, et les mises à jour peuvent être appliquées dans n'importe quel ordre tant que les entrées correspondantes sont calculées. L'utilisation de la programmation fonctionnelle fournit la concurrence et le parallélisme sans frais et facilite également le travail avec de grands modèles distribués. Il existe également certains paradigmes personnalisés dans lesquels la programmation fonctionnelle est étroitement liée à la théorie de l'information afin d'éviter le surajustement dans les modèles statistiques.
  • Manipulation des données peut être abordé avec une programmation fonctionnelle ou orientée objet. Dans la programmation fonctionnelle, tout est immuable, les algorithmes sont exprimés succinctement et il existe une correspondance de modèle native, mais la formulation de la commande de type expression mathématique est un art. L'aborder d'une manière orientée objet fournit des boucles récursives et itératives et une structure basée sur les classes qui facilite la mise à l'échelle pour des données plus volumineuses et de nouvelles fonctions. L'inconvénient est que les algorithmes et la logique du code ne sont pas exprimés de manière lisible. Bien que les deux paradigmes aient tendance à disposer d'un système de récupération de place automatique et puissent accéder et manipuler les bases de données de manière fluide, le choix de celui à choisir dépend fortement des connaissances du programmeur.

À emporter

Il y a une forte probabilité que deux développeurs soient en désaccord sur le meilleur style de codage pour n'importe quelle situation et aient des arguments valables pour étayer leur opinion. Ce qui est étonnant avec Python, c'est qu'il vous permet de choisir le paradigme de programmation qui vous convient le mieux dans une situation donnée.

Comme le démontrent les exemples ci-dessus, une tâche peut toujours être divisée en sous-tâches où chaque partie plus petite est codée dans un paradigme complètement différent. Le style mix-and-match fonctionne parfaitement tant que les packages utilisés sont minimes, que les entrées et les sorties sont clairement définies et que la complexité est modérée. Aucune règle ne dit que vous ne pouvez pas combiner les styles selon vos besoins. Python ne s'arrête pas au milieu de l'interprétation de votre application et affiche une erreur de style lorsque vous mélangez des styles.

Comme il n'existe pas de guide parfait pour choisir un style de codage correct pour un cas d'utilisation donné, la meilleure suggestion est d'essayer plusieurs paradigmes en pesant le pour et le contre jusqu'à ce que vous trouviez celui qui mène à une solution simple mais efficace. Il y aura des moments au cours de cette expérimentation où vous verrez qu'au lieu d'utiliser un seul style tout au long, une combinaison de paradigmes de programmation fonctionne mieux pour différentes parties d'une solution. Au cours de ce processus, il est également fortement recommandé de documenter les exigences et les essais de différents styles à partager avec la communauté et d'obtenir des commentaires. Les commentaires et suggestions aideront au développement ainsi qu'à vos coéquipiers et à tout futur développeur ajouté à l'équipe.

Jigyasa Grover a présenté Apprivoiser les styles de programmation Python à All Things Open, du 13 au 15 octobre à Raleigh, N.C.