Transcription
1. Introduction: Bonjour, je suis désolé, je suis le
bienvenu dans ce cours qui enseigne la programmation Python de niveau intermédiaire à
avancé. Il s'agit d'un cours organisé. Il ne s'agit pas d'une liste complète de toutes
les fonctionnalités
avancées possibles disponibles dans Python. Il contient les éléments qui,
selon moi , vous
seront les plus utiles si vous
souhaitez passer
à étape suivante de votre carrière dans le développement de
logiciels. Ce cours s'adresse à vous si vous avez une formation en Python, mais que vous souhaitez
en savoir un peu plus sur les fonctionnalités avancées
proposées par le langage. Je vais donc
parler de choses comme les indications de
type, le code simultané, classes de
protocoles,
les itérateurs, les générateurs et quelques autres
choses encore. Vous pouvez trouver tous
les exemples
de code utilisés dans le cours, dans l'onglet Projets
et ressources. Et il y a aussi un
petit projet amusant dans
lequel vous pourrez vous lancer à la fin.
Si vous aimez ce cours, vous aimerez peut-être aussi ma
chaîne YouTube ou Young Colts, youtube.com, Slash Iron Codes. J'y ai principalement
parlé de la conception de logiciels plusieurs modes de contenu
Python. Alors jetez-y un coup d'œil. J'espère que vous avez apprécié le cours
car vous êtes prêt. Plongeons-nous dedans.
2. Type Annotations 1/3: Je vais commencer
ce cours en parlant des systèmes de types. De nombreux langages de programmation
ont des types intégrés leur syntaxe et il existe différentes manières d'
examiner les systèmes de types. Et je veux parler de
quelques-unes d'entre elles aujourd'hui et de la façon dont cela se rapporte à la façon dont les types
de problèmes sont traités en Python. La première est donc que nous avons statique par rapport à des systèmes
de type dynamique. Et cette distinction concerne le
moment où les
informations de type sont acquises, que se passerait-il de manière statique ? Cela signifie que cela
se produit au moment de la compilation ou de l'interprétation
lorsqu'il est dynamique, cela signifie que les types
sont déterminés lors de l'exécution. Une autre distinction dont vous avez
peut-être entendu parler
est la frappe forte par rapport à la frappe faible. Et il s'agit plutôt de savoir à quel point strict de nouer des liens de
manière constante. Donc, par exemple convertit-il automatiquement les entiers en chaînes
de caractères ou inversement ? Il n'existe pas
de définition claire de ce qu'est exactement un système de saisie fort
par rapport à un système de saisie faible. C'est pourquoi nous
examinons généralement d'autres moyens de distinguer les systèmes de types, dont je parlerai dans une minute. Chaque langage de programmation
aborde les types différemment. Par exemple, Java est typé statiquement. Cela signifie donc que
si vous déclarez une variable de type
chaîne et une chaîne, puis que vous essayez de
lui attribuer un numéro. Ce n'est pas autorisé. Et la raison pour laquelle ce n'
est pas autorisé est que nous avons défini au moment de la
compilation que la variable serait de type chaîne, donc nous ne pouvons plus la modifier. Python, quant à lui,
est un conduit dynamique Il est
donc parfaitement possible de
définir une variable et de
lui donner une valeur de chaîne. Ensuite, nous lui
attribuons une valeur d'un type différent. Fondamentalement, le type n'est pas
associé à la variable, il est
associé à la valeur i. programme Python
très simple ici. Donc, si je définis une variable
x et que j'attribue une chaîne, et comme Python
est typé dynamiquement, je peux simplement lui attribuer une
valeur de différents types, dans ce cas un entier, et c'est très bien. Ce n'est absolument pas un problème. En Java, cela entraînerait bien
sûr une erreur. Maintenant, même si Python
est typé dynamiquement, il est également assez strict. On pourrait même dire que
c'est fortement dactylographié si nous avions
une définition pour cela. Donc, par exemple ce que je peux faire, c'est que si nous
avons la même variable X, nous pouvons faire bonjour plus cinq. Parce que si j'essayais de l'exécuter,
vous verrez que vous
obtiendrez une erreur indiquant que, hé, nous ne pouvons que concaténer
des chaînes et non des entiers. Cela signifie donc que Python
ne
convertit pas automatiquement ce nombre
cinq en une chaîne de cinq. Bien entendu, je peux le faire de
manière explicite. Donc, quand je lance à nouveau le programme, vous voyez
maintenant que cela
ne posera aucun problème,
car annuler
la conversion de type moi-même est différent d'un
langage comme JavaScript, qui vous permet de
faire hello plus five. Ensuite, je
vais simplement
convertir automatiquement le nombre
en chaîne. Et c'est également logique du point
de vue de JavaScript,
car ce que JavaScript est, bien
entendu, le
langage du Web. Et nous voulons nous
assurer que le client montre
toujours au moins
quelque chose de raisonnable. JavaScript fait donc de son mieux pour faire tout ce qu'il peut avec
les valeurs qu'il obtient. fonctionne pas toujours, mais cela signifie que même si
une page Web contient des erreurs, elle peut toujours afficher
quelque chose de significatif. Quelles sont les autres manières d'
examiner les systèmes de types, alors que l'un d'eux est manifeste par rapport à un système inféré, manifeste signifie que vous devez spécifier
explicitement le
type de variable, par exemple C ou Java ont un typage manifeste, nous devons spécifier
quel est le type. Déduit. La saisie signifie
que le type de la variable va être
déduit de la valeur. Et c'est exactement ce qui se
passe en Python. Donc, sur Python, nous n'avons pas besoin d' indiquer que dans ce cas, x est une chaîne et
rien d'autre. Pourtant, une autre façon de
considérer les systèmes types est nominale par rapport à la structure. Nominal signifie que
pour comparer si les types correspondent, le système de types examine
les noms dans leur intégralité. Donc, si nous avons des choses qui sont des chaînes, elles sont
toutes les deux du même type. Si nous avons deux
choses qui appartiennent à
la même classe ou que les classes sont également
de même type, les types correspondent. C'est nominal. Structurel signifie que nous
allons examiner
la structure des objets afin de comparer
si ces types correspondent. Ainsi, par exemple, si nous avons un objet
qui possède une propriété x, alors les types correspondent
à ceux d'un autre objet si l'objet possède
également la même propriété x. Il faut donc vraiment
regarder la structure de l'objet par rapport au
nom de l'objet. Alors, dans ce cas, que
possède Python ? Eh bien, ce n'est pas vraiment du typage
structurel, mais c'est un peu similaire. C'est ce que l'on
appelle le Duck Typing. La dactylographie en forme de canard est comme une
structure renforcée, mais ce n'est pas exactement la même chose. Le typage structurel est un système de type
statique qui compare les structures des objets lorsque vous
compilez le code. Doctype est dynamique, mais il ne prend en compte que les
parties qui comptent. Nous avons donc une certaine partie de l'objet à laquelle vous
accédez lors de l'exécution. Disons que vous avez
un objet avec une propriété x et une propriété pourquoi ? Et au moment de l'exécution, vous n' accédez à la propriété
X que si les types correspondent si l'objet possède cette propriété et que nous ne l'
examinons pas. Pourquoi, même s'il fait
peut-être partie du type statique, le typage en forme de
canard est en fait
ce que Python utilise. Il examine donc simplement les pièces
nécessaires pendant l'exécution. Correspondre. Python est prêt à fonctionner. J'ai ici un exemple qui
montre comment fonctionne la dactylographie en forme de canard. J'ai donc quelques
variables ici, ma chaîne ou ma liste,
mon dictionnaire. Et bien qu'ils
aient chacun des valeurs, vous voyez, nous avons une fonction de longueur qui peut imprimer la
longueur de ces éléments. Ce n'est donc pas une 11e année
car elle comporte 11 caractères. Cela s'appelle quatre parce qu'
il y a quatre éléments dans la liste et cela
va en imprimer trois. Et la façon dont
cela fonctionne est que la fonction de longueur
attend un objet. Vous pouvez déjà le voir
ici en taille de caractères. Et cela signifie que
cet objet doit être
associé à une méthode Lynn Dunder. Et c'est le cas pour les chaînes, les listes, les dictionnaires. Donc, si je l'exécute,
vous verrez qu'il n'y a aucun problème à exécuter ce code et à
simplement imprimer ce que je
voulais imprimer. Donc, ce qui se passe, ce sont
les dictionnaires, les listes et les chaînes de caractères. Bien sûr, ce sont des
types d'objets très différents, n'est-ce pas ? Mais Duck Typage
les accepte comme arguments
de la fonction length car la seule chose qui
est nécessaire ici ou à laquelle
on accède est la méthode length
dunder. Donc, tant que c'est
leur type de canard, Python est
prêt à fonctionner et qu'il l'accepte, même si ce type ne correspond pas exactement sur le
plan structurel car une chaîne n'est pas une liste et la liste
n'est pas un dictionnaire. Mais dans un canard, le système de saisie
fonctionne sans problème. Vous pouvez même aller plus
loin, par exemple ici, si le livre de classe
qui n'a pas d'initialiseur un auteur, un
titre et des pages. Et j'ai défini ici la méthode de
longueur moi-même, qui renvoie simplement
le nombre de pages. Ensuite, j'imprime en appelant la fonction de longueur
sur un objet de livre. C'est ce que vous voyez ici. Et puis, vous
voyez que lorsque je lance ceci, vous obtenez ceci en conséquence. Donc, dans ce cas, cela
fonctionne exactement de la même manière. La seule chose dont
la fonction de longueur besoin est un objet de type size. Cela signifie qu'
il devrait une méthode de don allégé,
ce qui permet à cette classe de se contenter de la moitié. Ce code s'exécute donc
sans problème car c'est
ainsi que fonctionne Duck Typage.
3. Type Annotations 2/3: Avec Python, vous
n'avez pas à spécifier explicitement de types
lorsque vous écrivez un objectif. C'est une bonne idée de
le faire, car cela vous aidera à
rendre votre code plus facile à lire. Et c'est en fait
très facile à faire. Par exemple, nous avons ici une
chaîne qui est HelloWorld, mais vous pouvez en fait indiquer à
l'aide d'indices de type ou d'
un type de notation quel est
le type de cette variable
particulière. Et vous le faites simplement
en écrivant une colonne puis vous tapez le type, vous tapez le type ici. Nous pouvons faire la même chose. Il s'agit donc d'une liste d'entiers. Je vais donc écrire
une liste d'entiers. Et si vous avez un type
générique comme celui-ci, vous pouvez utiliser les crochets
pour taper avec
le bouton droit de la souris derrière celui-ci. Et pour le dictionnaire,
c'est très similaire. Nous avons donc un dict et le premier, le type de clé est une chaîne, n'est-ce pas ? Nous avons 12,3, ce sont des chaînes et ce que cela indique vers la
valeur qui est un entier. Nous avons donc ici le type de
dictionnaire, ailleurs, pour
utiliser ce type de type. Et je vais vous dire que vous avez
besoin de Python 3.9 ou plus récent. Sinon, vous
devrez
écrire en tapant import,
dicter avec une majuscule, puis vous pourrez l'utiliser. Mais si vous utilisez une
version récente de Python, vous pouvez simplement écrire
ceci. C'est beaucoup plus rapide. C'est ainsi que vous
spécifiez les types. Bien entendu, la classe est aussi un type. Je peux écrire quelque chose comme ça, être un sous-type de livre. Et ça va être un livre. Ensuite, nous pouvons
lui transmettre certaines valeurs. Quelque chose comme ça. C'est ainsi que vous ajoutez des indices
de type lorsque vous
déclarez des variables. Maintenant,
ce n'est pas très utile car lorsque vous
regardez la ligne de code, vous pouvez déjà voir
que c'est un livre. Alors pourquoi devrions-nous
écrire cela, n'est-ce pas ? Ce n'est pas vraiment nécessaire, mais c'est vraiment
utile si vous avez des fonctions ou des méthodes et que vous souhaitez spécifier des indices
de type pour les arguments. C'est en fait ce que
vous voyez ici. Nous voyons donc que nous avons un
auteur de type chaîne. Nous avons un titre de
type chaîne et nous
avons des pages de type entier. C'est très utile
car lorsque nous appelons l'initialiseur de livres ici, vous pouvez voir que j'utilise du code
VS dans ce cas. Je reçois donc déjà les informations de type
dans l'en-tête. Maintenant, je sais exactement
ce que je dois fournir. Cet auteur est
censé être une chaîne et vital est
censé l'être également. Et met en page un intérieur. Vous verrez cela comme
un type de retour ici. L'initialiseur de livres
ne renvoie donc rien,
et c'est correct. n'y a pas de
déclaration de retour ici. Vous pouvez également l'écrire
explicitement si vous le
souhaitez, comme ça. Il renvoie donc aucun et une longueur. Si vous regardez cela,
cela renvoie un entier. Nous pouvons donc également le spécifier
explicitement. Une chose que vous pourriez vous demander est
ce qui se passe si nous spécifions un
type incorrect, par exemple, nous avons
ici une variable
de type chaîne, n'est-ce pas ? Et nous attribuons la chaîne,
donc tout est correct. Mais que se passe-t-il si je transforme
cela en un entier, par exemple, ce n'est clairement pas
un entier, n'est-ce pas ? Donc, si nous exécutons cela, vous voyez que le code s'exécute totalement sans
aucun problème, même si le type
est complètement erroné. C'est pourquoi Python
ne prend pas en compte ces types lorsqu'il exécute
réellement le programme. Ils sont
là uniquement pour nous aider, en tant que développeurs, à comprendre
où se
situent les problèmes dans notre programme.
Vous voyez, nous n'avons même pas d'
erreur ici et c'est
là que les paramètres de VS Code
peuvent nous aider à spécifier la rigueur avec laquelle
nous voulons que notre système de
vérification de type soit ouvert dans
notre IDE. Maintenant, les paramètres
de l'espace de travail dans VS Code et Dairy indiquent qu'
un moule de vérification du type de points Python Dot Analysis est désactivé. Vous pouvez donc modifier cette valeur pour déterminer dans quelle mesure la vérification
de type doit être stricte. Et il y a essentiellement
trois options. Il y a Off basic et Stricter. Permettez-moi donc de le modifier en strict. Comme ça. Revenons maintenant à mon
dossier et osons voir, hé, maintenant nous
avons un problème. Vous voyez, ma chaîne
est un entier, mais nous lui attribuons une chaîne. Et vous voyez également que nous obtenons une erreur d'
incompatibilité fournie par les pilotes, qui est la surface du
langage Python de VSCode. Permettez-moi donc de
le remplacer
par une chaîne ou vous, d'ailleurs, vous le verrez
également ici. C'est ma chaîne qui est un entier. Je vois qu'ici, nous avons
également un problème selon lequel un int peut être
attribué car il
n'est pas hors type. Size in n'a pas longueur (méthode dunder). Remettons donc cela en chaîne et nous verrons ensuite
que le problème a été résolu.
4. Duck Typing avec les cours de protocole: Un type assez spécifique à Python dont je veux
parler avec vous, et c'est la classe de protocole. Nous avons donc vu dans l'autre exemple que
nous pouvons avoir de la classe. Et la classe est, bien
sûr, un type. Mais ce qui arrive souvent,
c'est que vous utilisez des classes et des objets d' un type particulier partout
dans votre code, n'est-ce pas ? Voici donc un exemple où nous avons
une classe appelée
clients
de messagerie ou
disons qu' il s'agit d'un système d'
envoi de courrier électronique. Et vous voyez, ce qui se passe ici, c'est
que nous avons
l'initialiseur qui obtient un tas d'
informations comme les identifiants , les
mots de passe, etc. Mais à l'intérieur de l'initialiseur, nous créons un serveur SMTP. Nous avons ensuite essayé d'obtenir l'
hôte et le port à partir de l'objet serveur SMTP
que nous venions de créer. Ensuite, nous faisons
certaines choses, comme vérifier le nom d'utilisateur et le mot de passe, stocker ces deux adresses
, etc. Ensuite, nous avons
quelques méthodes comme se connecter au serveur, quitter le serveur
et envoyer un message, envoyer un e-mail via cet
internaute avec des éléments utiles comme l'
ajout systématique des deux adresses , etc. Nous avons donc beaucoup de types ici. Vous voyez que nous avons ici
les types de retour
qui sont pour la plupart non. Nous utilisons également d'autres types d'annotations de type
ici, par exemple,
cela signifie que la connexion peut être
une chaîne ou qu'elle peut être connue. C'est donc ce que
l'on appelle également la syntaxe de type union. Cela signifie que vous pouvez combiner
plusieurs types et
qu'à un type ou par défaut, nous
lui attribuons la valeur none. Vous voyez également que nous nous appuyons
ici sur le type SMTP, qui provient de
SMTP lib, n'est-ce pas ? Ce n'est pas un
problème en soi, mais cela signifie qu'il n'y a
aucune dépendance entre vos clients de messagerie et une classe SMTP
très spécifique. Si vous souhaitez utiliser
une bibliothèque pour cela, vous
devez accéder à l'implémentation de
la classe et corriger les références au SMTP,
puis supprimer cette importation. Une autre méthode
consiste à utiliser des protocoles. Et avec le protocole,
ce que vous faites, c'est une très belle extension
du mécanisme de saisie Duck. En Python avec protocole, vous spécifiez
la structure de l'objet. C'est donc la partie structurelle de la dactylographie en
forme de canard et ce à quoi vous vous attendez. Et puis le système de typage
Duck de Python va correspondre à
cela au moment de l'exécution. J'ai donc ici un autre
exemple où j'ai utilisé ce mécanisme. Et c'est
exactement la même classe. Nous avons donc à nouveau ici
le client de messagerie, mais vous voyez maintenant qu'il y a
une autre classe qui est écrite au-dessus et qui s'
appelle Where are we ? Serveur de messagerie ? Un serveur de messagerie est
une classe de protocole. Vous voyez que nous l'avons
importé à partir de la saisie. Et puis il y a quelques propriétés et méthodes
que j'ai définies. Il y a donc l'hôte et
les flèches pour connecter les méthodes. Ce sont donc les
méthodes standard qui constituent également l'essence
de la classe de serveur B. Mais maintenant, nous transmettons aux clients
de messagerie une
instance de ce serveur SMTP, puis nous l'utilisons simplement. Et ce
qui est bien, c'est que comme nous fournissons désormais simplement le
protocole en tant que type, nous pouvons utiliser le serveur SMTP
comme nous le faisions auparavant. Il suffit de le créer en
dehors du client de messagerie. C'est ce qu'on appelle
l'injection de dépendance, d'ailleurs. Et si nous voulons le
remplacer par autre chose, par exemple, nous voulons utiliser
un autre serveur SMTP ou peut-être utiliser un faux serveur SMTP afin pouvoir écrire des
tests logiciels pour cette classe. Eh bien, alors nous pouvons
simplement fournir cela. Et tant que la
classe que nous fournissons, l'objet
qui la fournira
est conforme à ce protocole. Donc, tant qu'il
possède ces méthodes et que doctype y
correspond, nous pouvons l'utiliser en
combinaison avec un client de messagerie. Et nous avons également perdu l'importation très
spécifique ici depuis la bibliothèque SMTP, car maintenant nous nous appuyons simplement
sur un protocole. Le protocole vous permet donc d'
introduire une certaine abstraction dans votre code afin que vous n'ayez pas à inquiéter d'avoir
de nombreux couplages, de nombreuses dépendances
directes avec des bibliothèques de bas niveau, des pantalons
serrés, comme je viens de
vous le montrer , un outil vraiment utile
pour améliorer la lisibilité de
votre code qui peut être bibliothèques de bas niveau, des pantalons
serrés, comme je viens de
vous le montrer, un outil vraiment utile
pour améliorer
la lisibilité de
votre code qui peut être
utile si vous travaillez
en équipe sur ce code ou si vous écrivez le code, puis
quelques mois plus tard, vous y
revenez et vous essayez de
comprendre ce qui se passe et
ce que vous êtes censé transmettre
comme arguments à une
fonction ou quelque chose comme ça. Les conseils de saisie sont très
utiles pour clarifier cela
et vous assurer que vous commettez moins d'
erreurs en tant que développeur. Par exemple, voici une
fonction de calcul de statistiques qui obtient des arguments. En fait, nous n'avons aucune idée, si vous regardez les dysfonctionnements gérés, de ce que nous sommes
censés en faire Il y a des utilisateurs,
des plantes et des produits, mais quels sont ces éléments ? S'agit-il de dictionnaires
ou de listes ? Est-ce une cellule vers un numéro ? Nous ne le savons tout simplement pas. Si vous fournissez des indices de saisie. C'est beaucoup plus facile à voir. Nous pouvons immédiatement voir ce que
nous devons fournir et le vérificateur de type
intégré
aux pylônes VSCode. Mais d'autres éditeurs ont également
un correcteur de type comme celui-ci. Cela vous aide à comprendre
où se trouvent les flèches et les
résoudre avant
même
de devoir exécuter votre programme pour le savoir. Ainsi,
les caractères contribuent à la lisibilité de votre code et vous
aident également à détecter les erreurs plus tôt
dans le processus de développement Les mains
de saisie
indiennes vous feront gagner beaucoup de temps. Je
vous recommande donc vivement de commencer à
les utiliser davantage si vous ne l'avez pas déjà
fait. Ainsi s'achève cette
leçon sur les indices de frappe. Dans la prochaine leçon, je vais
approfondir les classes et vous
montrer quelques choses
très puissantes que vous pouvez faire avec elles en Python.
5. Cours de premier niveau 1/4: Dans cette leçon, je
vais parler des classes et je vais vous
montrer différentes choses que vous pouvez faire avec elles en Python. J'ai donc ici un exemple très
simple. C'est une personne de classe,
rien de spécial. verre presque vide
a juste un initialiseur et reçoit un nom
et une adresse. Comme vous pouvez le voir, ce sont des cordes. J'utilise des indices de frappe ici. Je devrais probablement ajouter, puisque l'initialiseur ne
renvoie rien. Et puis j'utilise une fonction de
génération d'identifiant. Vous pouvez voir cette
fonctionnalité
ici pour générer une
sorte d'identifiant. Vous pouvez donc imaginer cela
comme une base de données simplifiée. Ensuite, nous avons un
nom et une adresse, et nous avons également une liste vide d'adresses e-mail. Voici donc le cours
personnel, Basic. Et puis j'ai
la fonction principale où je crée une personne avec un nom
et une adresse, puis j'imprime cette personne. Donc, lorsque j'exécuterai
ce code, voici ce que nous allons
obtenir des résultats. Je suis donc en train d'imprimer un objet personnel. Vous pouvez le voir
ici. Maintenant, ce n'est pas une
information très utile, non ? Parce que nous obtenons simplement
une adresse mémoire. Nous n'avons aucune idée de ce qui est
réellement contenu dans l'objet Person, ce serait bien si nous pouvions
réellement le voir. Et bien sûr, c'est
possible en Python. Pour ce faire, vous
pouvez principalement ajouter une méthode STR ou
wrapper dunder. J'en parlerai davantage dans une minute. Mais dans l'ensemble, il existe
une manière différente de définir les classes en Python. Dans l'ensemble, c'est un peu plus simple. Je me sens un peu plus facile à lire et c'est en
utilisant des classes de données. Mais on pourrait dire que les
classes de données sont vraiment plus orientées vers les classes
orientées vers les données, n'est-ce pas ? Des points de données structurés, des
vecteurs, etc. Au lieu d'un bouton d'une surface de chaussée ou d'une
autre classe axée sur le comportement. Mais il ajoute de nombreux mécanismes
pratiques,
tels qu'un moyen beaucoup plus simple
de définir des attributs. Vous pouvez les comparer
beaucoup plus facilement. Vous pouvez les imprimer
beaucoup plus facilement. Ces éléments sont donc utiles
pour presque tous les types de cours. Comment transformer une personne
en classe de données ? C'est en fait très simple. Donc, ce que je vais faire,
c'est à partir des classes de données, je vais importer la classe de données, qui est le type que
nous allons utiliser ici. Et puis, au lieu de définir
une personne de cette manière, nous allons écrire une classe de
données au-dessus. Et maintenant, ce que je peux faire, c'est spécifier les
variables d'instance ici. Nous avons donc un nom,
qui est une chaîne, et nous avons une adresse, qui est également le printemps. Et nous allons avoir une
liste d'adresses e-mail. C'est une liste de chaînes, non ? Et la carte d'identité. Nous pouvons également le faire, je vais vous montrer
comment le faire dans une minute. Mais si je supprime cela, vous pouvez voir qu'
il est beaucoup plus facile de
comprendre ce qu'est réellement une
personne car nous pouvons simplement regarder haut et nous voyons immédiatement les
noms des variables d'instance et leurs types. C'est pourquoi les
classes de données sont vraiment utiles. Et j'y
reviendrai dans une minute. Permettez-moi simplement de faire un commentaire. Mais maintenant, si je crée une
personne de cette façon, cela se passe
exactement de la même manière. Les classes de données génèrent donc
en fait un initialiseur basé sur les valeurs de ces variables d'
instance. Quand je l'exécute, vous pouvez voir qu'il imprime maintenant la personne. Mais vous voyez également
que cette classe de données a
déjà résolu ce problème si vous imprimez l'objet qui va imprimer quelque chose de significatif, et elle le fait en implémentant les méthodes wrapper dunder. J'en parlerai davantage
dans une minute également. Alors, comment ajouter ces
autres éléments à la classe de données ? Bien sûr, nous avons l'
ID, qui est une chaîne, mais nous aimerions maintenant lui attribuer une valeur générée
par cette fonction. Pour ce faire, nous devons utiliser
la fonction de champ qui se trouve
également dans les classes de données. Et ce que je fais ici,
c'est que l'identifiant est égal à un champ et
que la fabrique par défaut, c'est-à-dire que
la
fonction qui crée la valeur pour nous, sera generate ID. Maintenant, ce
qui se passe, c'est que pour
calculer cette valeur, la classe de données va
appeler cette fonction
pour la calculer. Et comme cette valeur
a désormais une valeur par défaut, nous devons la mettre ci-dessous. Les autres cellules n'
ont pas de valeur par défaut. Alors on y va. Maintenant, quand je l'exécuterai à nouveau, vous verrez que ma
personne a maintenant un nom, une adresse, mais maintenant elle a aussi
un identifiant qui a été généré en appelant
la fonction generate ID. Vous pouvez également simplement fournir
une valeur par défaut, par exemple supposons que nous ayons
ici une variable d'instance
active qui est une valeur booléenne. Et la valeur par défaut sera définie sur true. Désormais, une personne est active
par défaut. Et vous voyez qu'il est désormais également inclus dans l'
objet Person, ici même. Que pouvons-nous faire d'autre maintenant ? Eh bien, nous avons également
les adresses e-mail répertoriées ici, alors ajoutons-les également. Et puis ajoutons également
une valeur par défaut ici. Maintenant, vous pourriez être
tenté d'écrire ceci. Ce n'est pas une bonne idée car la façon dont Python
fonctionne est que
cette valeur est en fait générée une seule fois
au moment de l'interprétation. Donc, si vous l'attribuez
comme valeur par défaut et
c'est la même raison pour
laquelle vous ne devriez pas
attribuer de liste vide comme valeur par défaut dans les fonctions. Vous pourriez avoir un comportement
inattendu, car toutes ces listes vides
font essentiellement
référence au même objet
, ce que vous ne voulez pas. Donc, vous pouvez
également définir un champ ici et simplement dire
que la valeur par défaut, cette usine par défaut,
sera l'initialiseur de la liste, comme ceci. Désormais, chaque personne aura
également une liste d'adresses e-mail qui par défaut, sera vide. D'autres choses que vous pouvez faire avec des classes de données qui
sont vraiment intéressantes. Eh bien, la première est que, comme nous l'avons vu, cela génère l'initialiseur. Nous avons donc ici une personne. Il a donc un nom, une adresse, identifiant, une adresse active et une liste
d'adresses e-mail. Mais peut-être ne
voulez-vous pas que l'identifiant soit là, vous voulez qu'il soit
toujours généré. Ce qui est logique, non ? Nous ne le savions pas, nous ne voulons pas
spécifier ces identifiants de manière explicite. Nous voulons qu'il soit
généré automatiquement. Donc, ce que vous pouvez faire, c'est
simplement fournir à la fonction de champ qu'elle contient
la valeur false, comme ceci. Et maintenant, lorsque vous regardez à
nouveau la définition
de Denise Lives, vous constatez que le champ d'identification
ne fait plus partie de
l'initialiseur, mais qu'il
fait toujours partie de la personne nous voyons
ici et qu'il est
généré automatiquement. Cela vous permet donc d'
avoir un certain contrôle sur ce à quoi ressemblera l'initialiseur tout en ayant cette
très belle vue d'ensemble de tous les attributs de l'
instance. Une autre chose que vous
pourriez faire est peut-être d'ajouter une
chaîne de recherche à cette personne. Supposons que nous ayons
une chaîne de recherche. Variable d'instance,
oui, c'est une chaîne. Et ce que nous voulons maintenant, c'est
que la valeur ici soit dérivée du nom
et de l'adresse. C'est donc ce que nous
voulons être capables, Sergio. Mais bien sûr, ici, nous
pouvons
encore définir cette valeur car nous ne
disposons pas de ces valeurs. Il s'agit simplement
d'une spécification des attributs de l'instance. Donc, ce que nous pouvons faire à la
place,
c'est simplement fournir un champ et
le définir comme étant faux, car nous ne voulons pas pouvoir fournir la chaîne de recherche dans le
cadre de l'initialiseur. Mais alors, ce que nous pouvons faire,
c'est y définir un coup de pouce. Les méthodes Dunder ne renvoient aucune
chaîne de recherche à points automatique égale. Ensuite, nous allons simplement
construire la chaîne self.name et l'adresse self point, comme ceci. Maintenant, ce qui se passe, c'est
que les deux entrées sont appelées après la création de l'objet
. C'est alors que nous avons le
nom et la valeur de l'adresse, puis nous pouvons calculer
la chaîne de recherche. Donc, lorsque j'exécute ce code, encore une fois, vous voyez que nous avons maintenant
toutes ces valeurs ici, mais nous voyons également que nous avons
une chaîne source qui est le nom plus un espace,
puis l'adresse. Alors, que pouvons-nous faire d'autre ? Peut-être que nous ne voulons pas du tout que la chaîne
de recherche apparaisse lorsque nous imprimons la
personne parce que c'est sorte de double
inflammation, n'est-ce pas ? Vous pouvez imaginer que si
la classe de personnes augmente, cette chaîne
de recherche deviendra très longue. Donc, au lieu de l'imprimer, chaque fois que nous imprimons person, nous pouvons également ajouter ici un
rappeur égal à faux. Et cela signifie simplement que
lorsque nous imprimons la personne chaîne de
recherche ne fera pas partie de la représentation. Il ne sera pas inclus.
C'est ce que vous voyez ici. Et pour clarifier, cette chaîne
de recherche est en fait quelque chose d'
interne à la classe. Vous pouvez également décider de mettre un trait de soulignement
devant, comme ça. Et maintenant, nous établissons cette
distinction encore plus clairement dans la
définition de classe elle-même. Nous pouvons également
contrôler la façon dont les objets sont créés. Nous avons donc ici une personne, nous fournissons un nom et une adresse, mais si vous le souhaitez, nous pouvons supprimer ces arguments, noms de
mots clés ici et maintenant, cela
fonctionnera bien sûr toujours. C'est ainsi que les classes fonctionnent par
défaut en Python, n'est-ce pas ? Et si vous vouliez vous
assurer de
ne pouvoir le fournir qu'en utilisant arguments de
mots clés que
vous devez toujours écrire, nom égal et adresse égal. Eh bien, vous pouvez le faire en passant un argument ici au décorateur de classe de
dates, et c'est
uniquement un mot clé et par défaut, c'est faux, mais nous
pouvons le définir sur true. Et maintenant, nous voyons que
nous obtenons en fait une erreur car elle
attend des mots clés. Maintenant, nous devons écrire que le
nom est égal à John et l'adresse est égale à
123 rues principales. Pour que cela fonctionne, cela n'a aucun effet sur le résultat réel, le résultat réel, mais cela affecte la façon dont nous
pouvons créer des personnes. Et cette rigueur supplémentaire peut parfois être un outil utile. Vous pouvez également
geler une classe de données. Cela signifie que vous pouvez modifier l'objet une fois
qu'il a été créé. Et nous le faisons en fournissant les produits surgelés ainsi. Mais maintenant, quelque chose
d'intéressant se passe. Vous voyez que notre idée de chaîne
de recherche
ne
fonctionne plus car, bien sûr nous avons maintenant
un objet figé, ce qui signifie que nous pouvons le modifier, mais nous le
modifions toujours après sa création. Je vais
vous montrer une autre façon d'aborder cela dans une minute. Donc, pour le moment, permettez-moi de supprimer ceci. Nous utiliserons
autre chose plus tard pour résoudre
ce problème. Maintenant, quand je l'exécute,
bien sûr, cela fonctionne toujours,
mais maintenant, quand j'essaie de
modifier la personne, le nom de point de la
personne est égal, vous voyez que nous ne sommes
pas autorisés à le faire. La personne est gelée et reçoit une
erreur lorsque vous l'exécutez Vous voyez également que nous obtenons une erreur d'instance
gelée. C'est très utile
si vous voulez vous
assurer que si vous
utilisez certaines données, vous ne les
modifiez pas accidentellement. Mais comment résoudre ce problème
de chaîne de recherche maintenant, car nous ne sommes pas autorisés à modifier cet objet après
sa création. Eh bien, une chose que vous pouvez faire
est d'utiliser des propriétés à la place.
6. Cours de premier niveau 2/4: C'est un autre ajout très
intéressant aux classes qui vous permet de les
rendre beaucoup plus puissantes. Ce que vous pouvez faire, c'est qu'
au lieu de l'utiliser, vous pouvez utiliser une propriété
pour définir un terme de recherche. Je vais donc avoir
une propriété ici, et disons que c'est une chaîne de t-shirts
haut de gamme. C'est presque comme une méthode. Et cela renverra une chaîne. Et je vais simplement
le supprimer ici. Et la chaîne
de recherche sera une chaîne f
contenant self.name, self.age, address, etc. Il est donc toujours gelé. Mais
maintenant, supprimons cela à nouveau. Quand j'imprime la personne. Eh bien, la chaîne de recherche n'est pas
là à cause de la propriété, mais nous l'avons, donc je
peux imprimer le point personnel, la chaîne de recherche, etc. Il se plaint qu'il s'
agit d'un membre privé maintenant, mais comme vous le voyez, il fonctionne réellement dans ses publications. sûr, si vous souhaitez que la chaîne de recherche soit plus accessible
au public, vous pouvez bien sûr
supprimer ce trait de soulignement de cette manière. Et maintenant que l'erreur des pylônes se
répète autour de nous, nous obtenons toujours les mêmes résultats. Donc, une fois que nous avons ajouté, voici une propriété en lecture seule,
également appelée getter. Et il est lu uniquement parce que nous ne
pouvons rien lui attribuer. Si la
chaîne de recherche par points est égale à une valeur élevée, vous verrez que nous obtenons une
erreur indiquant que nous ne pouvons pas attribuer un membre à une
propriété qui n'est pas autorisée. Ce que vous pouvez faire si vous souhaitez que
la chaîne de recherche soit modifiable, c'est d'ajouter un setter. Et comme la source, par exemple , la
propriété, c'est
très facile en Python. Nous écrivons simplement
la chaîne de recherche point, puis nous avons
ici un setter de points. Ensuite, nous redéfinissons simplement le
même nom de propriété. Mais il accepte un argument
qui est la valeur. Cette coque est une chaîne. Il va renvoyer une valeur nulle. Et puis ici, nous
pouvons définir la valeur. Bien entendu, cela
ne fonctionnera pas parce que nos classes de données sont bloquées, accord, nous pouvons donc tout
modifier. Donc, si nous supprimons cela
, nous pouvons maintenant stocker des choses. Et comment vous pourriez stocker une valeur dans l'objet
si vous le vouliez. Mais bien sûr, nous n'en avons pas vraiment
besoin dans le cas de la chaîne source
car nous
renvoyons simplement une valeur calculée ici, j'ai un autre exemple
ici qui a un peu plus de sens en
termes de propriété. J'ai donc un clip vidéo de classe qui contient des minutes et des
secondes, un titre. Et vous voyez que nous sommes une
propriété appelée durée. Et en gros, en
fonction du nombre de
minutes et du nombre de secondes, on obtient
un total de secondes. Et puis nous pouvons
également avoir un setter qui définit un nombre de secondes. Et cela utilise essentiellement
la fonction div mod pour calculer la
valeur supposée des minutes et des secondes. Vous voyez donc ici un exemple d'utilisation
d'une propriété, un getter et d'un setter pour contrôler la façon dont
les valeurs sont stockées. Objet, dans ce cas, minutes et secondes
du clip vidéo. Et voici un projet
vidéo qui contient une liste de clips vidéo. Et encore une fois, il s'agit d'un champ utilisé comme liste d'usine par défaut. Nous avons une
valeur par défaut pour notre titre, puis nous avons également une
propriété correspondant à la longueur totale, savoir la somme de
chacun de ces clips, le nombre de
minutes et de secondes. Ensuite, j'ai une fonction
principale simple où
j'ai deux clips. L'un est un clip vidéo d'
une minute et 30 s, un autre clip vidéo
de 2 min et 30 s. Et puis je crée un projet
contenant ces deux clips. J'imprime la longueur totale
, puis j'utilise le paramètre de durée pour
changer la durée du clip, durée 220 s,
soit 2 minutes en fait. Ensuite, nous pouvons imprimer la longueur totale du
projet. Et puis quand je lance ça, voici ce que nous obtenons. Nous obtenons donc 240, mais ensuite nous
passons de 1 min à 2 min. Cela fait donc trente secondes de plus. Cela fait donc 270 s
qui sont en cours d'impression. Ou vous pouvez également voir que
si j'imprime le clip ici, Friends en extrait un et je
réexécute ce code. Vous voyez qu'après avoir
mis à jour le clip, vous voyez que nous
avons 2 minutes et 0 s. Et c'est exactement
la durée de chaque dose. Et si vous
regardez un projet vidéo, nous pouvons le
simplifier encore plus, car voici les minutes d'
Eclipse point, blocs de points, les secondes. Eh bien, nous pouvons simplement utiliser le temps qu'elle passe ici
pour le raccourcir encore. Ensuite, nous allons obtenir exactement le même
résultat qu'avant. Ce sont donc des propriétés qui
peuvent être utiles pour obtenir une valeur calculée
sans avoir à
stocker cette valeur. Ils vous aident également à masquer certaines données de bas niveau dans une classe, par exemple si vous avez des
minutes et des secondes en interne, mais que vous utilisez simplement les
secondes effectuées en externe, un getter et un setter
de propriétés vous aideront à y parvenir.
7. Cours de premier niveau 3/4: encore deux choses dont je
voudrais parler avant de terminer cette leçon. L'un est une chaîne contre une enveloppe. Nous avons donc constaté que si vous avez une classe de données telle que
cette classe de personnes, et que nous imprimons la personne que
nous voyons, nous obtenons une sorte de version conviviale pour les
développeurs de ce qu'est réellement la personne,
qui est utile pour le débogage ou si vous souhaitez verrouiller
quelque chose ou quoi que ce soit d'autre. Et c'est exactement ce que l'
emballage est censé faire. Wrapper est censé vous donner représentation
d'un objet conviviale pour les développeurs. L'idée est même
que vous devriez être capable de
stocker cette représentation dans un fichier et qu'elle contienne suffisamment
d'informations pour plus tard, si vous souhaitez la lire à nouveau dans
un fichier et recréer l'objet qui soit
différent d'une
représentation conviviale. Ce n'est pas quelque chose que
vous voulez qu'un utilisateur voie parce que c'est un peu
difficile à lire, à écrire. Et c'est là que la méthode
dominante des chaînes est quatre. Donc, si vous souhaitez également avoir une
représentation plus conviviale d'un objet, vous pouvez utiliser les méthodes
string dunder. classe de données ne l'ajoute pas, mais vous pouvez l'ajouter vous-même simplement en ajoutant les méthodes
String Dunder. Et bien sûr, cela va
renvoyer une chaîne, n'est-ce pas ? Et que voulons-nous retourner ? Disons que
nous voulons simplement
imprimer le nom de la personne. C'est donc un
nom à point fixe, comme ça. Maintenant, lorsque nous exécutons à nouveau
ce programme, vous voyez qu'il
affiche simplement le nom. Et c'est parce que String
Dunder l'emporte sur le rappeur, non ? Donc, si vous n'avez pas de chaîne, mais que vous avez un rappeur Python utilisera un wrapper. Si vous avez une chaîne, elle l'
utilisera à la place. Mais que faire si vous souhaitez toujours imprimer la
version enveloppante de la personne ? Eh bien, il existe plusieurs façons
de procéder. La première est que vous pouvez utiliser la fonction
wrapper de cette manière. Et cela va simplement appeler la
méthode wrapper dunder, puis renvoyer sous forme de chaîne
que nous pouvons maintenant imprimer. Donc, si je fais cette marguerite, nous aurons notre personne, une personne sympathique pour les
développeurs. Encore une fois, vous pouvez également
utiliser des chaînes de caractères. Donc, si vous avez une
chaîne f comme celle-ci, et maintenant, bien sûr,
imprimez simplement la personne. Encore une fois, cela affichera
la méthode String Dunder, mais vous pouvez en fait
utiliser le point d'exclamation R. Et dans une chaîne F,
cela affichera également la version wrapper des objets sur lesquels vous avez un
certain contrôle sur
le Et dans une chaîne F,
cela affichera également la version wrapper des objets sur lesquels vous avez un
certain contrôle sur
le type
de contenu imprimé, même si vous avez
peut-être à la fois des méthodes wrapper et String Dunder.
C'est bon à savoir.
8. Cours de premier niveau 4/4: La dernière chose que je
veux vous montrer est un moyen simple d'améliorer la vitesse d'accès aux
éléments de vos objets. Et c'est en utilisant des machines à sous. Normalement, Python utilise
un dictionnaire pour stocker les valeurs des
variables d'instance d'un objet. Et l'accès aux dictionnaires est rapide, mais pas incroyablement rapide. Et si ce n'est pas si rapide, c'est parce que c'est
assez dynamique. Vous pouvez ajouter des clés et des
valeurs à tout moment. Vous pouvez donc
décider de
modifier dynamiquement l'objet et d'ajouter nouvelles
variables d'instance à tout moment. Python est un langage très dynamique. N'oubliez pas qu'en ce qui concerne les créneaux horaires, vous convenez avec l'interprète que vous allez
être un peu plus strict. Vous allez avoir un
ensemble fixe de variables d'instance. De ce fait, Python peut optimiser
les choses et y accéder beaucoup plus rapidement. Maintenant, dans la plupart des cas, vous
aurez
en fait un nombre fixe de variables d'
instance. Vous ne voulez pas
changer d'objets tout le temps,
partout, n'est-ce pas ? Ça va tourner au bordel. Donc, si vous le faites et
que vous en utilisez beaucoup, ce sera
en fait beaucoup plus rapide. Voici donc un exemple très simple qui utilise à nouveau des classes de données, une option d'emplacements. Ainsi, si vous
avez une classe de données, vous pouvez simplement définir les
emplacements sur true, comme je le fais ici. Ensuite, il utilisera des
machines à sous au lieu du dictionnaire
traditionnel. J'ai donc une version de
la classe person, n'en utilise pas beaucoup et une version de la première classe
qui les utilise. Et puis j'ai une fonction, celle Elite qui
permet d'attribuer des créneaux à une
personne ou à une personne, et qui permet de
définir l'adresse, lire l'adresse et de
la supprimer , comme
une sorte de point de référence. Et puis j'ai la fonction
principale qui consiste à créer des personnes,
des machines à sous et
une personne normale. Ensuite, j'utilise
Time it to repeat pour appeler la
fonction Get Set Delete de la personne. Beaucoup de fois, dans ce
cas, 1 million de fois. En fait, je prends la
valeur médiane pour obtenir les performances médianes
et je vais
imprimer combien de temps. C'est bon, les performances s'
améliorent. Au fait, ce
truc est partiel. J'en parlerai dans
la prochaine leçon. Alors restez à l'affût. Alors laissez-moi le lire maintenant, nous
pouvons voir ce qui se passe. constatons maintenant que
lorsque nous n'avons pas d'emplacements toutes ces opérations d'accès, de lecture, d'
écriture et de suppression
prennent 0,06 s avec les emplacements, cela prend 0,05 s. donc une
amélioration des performances de près de 20 %, surtout si vous
traitez de nombreuses données, alors cela
aura vraiment un impact important si vous effectuez
ces opérations partout. C'est donc très simple, il
suffit de définir les emplacements sur true lorsque vous définissez
votre classe de données. Vous pouvez désormais bénéficier de
cette amélioration, car
les emplacements d' amélioration de la vitesse utilisent
également un peu moins de mémoire. Il y a cependant quelques
mises en garde. La première est que si vous utilisez
plusieurs emplacements d'
héritage , cela peut entraîner des problèmes. Soyez donc très prudent avec
cela, mais vous devez, dans tous les cas, faire attention à
l'utilisation de l'héritage multiple. Et une autre chose est
que vous les comptez dynamiquement en ajoutant ou en supprimant des variables d'
instance, deux objets parce que emplacements étaient un
peu plus stricts. Mais je pense que dans l'ensemble,
c'est une bonne chose. Cela conclut cette leçon où je
vous ai montré quelques choses
plus puissantes que vous pouvez
faire avec les classes en Python. Dans la leçon suivante,
je vais
parler de ce que vous pouvez
faire avec les fonctions. Et je vais également
examiner de plus près certains outils fonctionnels de
Python pour vous aider à le faire.
9. Fonctions de premier niveau: Dans cette leçon, je veux
parler des fonctions et de certaines des choses
les plus puissantes que vous pouvez faire avec les fonctions en Python, comme nous l'avons fait avec classes et dans la leçon précédente. En Python, en gros, tout est un objet, n'est-ce pas ? Nous avons des entiers, des chaînes de caractères, des
classes dont vous
pouvez créer des objets. Même une fonction est un objet, c'est un objet de type double. Et vous pourriez en fait,
si vous vouliez créer une classe dotée d'un
appel à des méthodes dunder, cette classe est également une classe de rappel qui
se comporte également comme une fonction. En fait. Voici un exemple très simple j'ai une classe de clients, c'est une classe de données. Si vous dormez avec un nom, un âge et leur
fonction, voici une promotion appelée Envoyer un e-mail,
qui permet d'obtenir une liste de clients et qui est
utilisée pour
passer en boucle les clients
qui consultent le client. Si l'âge est d'environ 50 ans, le client est
éligible à la promotion. Et si l'
âge du client est supérieur à 50 ans, il est
éligible à la promotion. Et en fonction de cette valeur, nous imprimons quelque chose de
différent à l'écran. Ensuite, j'ai une fonction principale
qui crée une liste de clients, puis envoie des promotions
par e-mail à
ces clients.
Au moins ceux de plus de
50 ans ont contourné cette
procédure, puis voici ce que nous obtenons. Il vérifie donc chaque client ,
puis indique s'
il est éligible ou non pour envoyer promotion
par e-mail. Il s'agit
d'une fonction appelable, qui permet d'obtenir la liste des clients
et des retours, aucune. Et bien sûr, c'
est une utilisation très basique de la fonctionnalité en Python, n'est-ce pas ? Mais comme la
fonction est un objet, vous pouvez en fait faire beaucoup
plus de choses avec elle. Par exemple, vous pouvez
transmettre une fonction à une autre fonction ou même demander une fonction de renvoyer une autre
fonction en conséquence. Et c'est ce que nous faisons. C'est
lorsque vous utilisez ce que l'on appelle les fonctions de
commande supérieure. Par exemple, ici, nous vérifions que si le client est
âgé d'environ 50 ans, il est
éligible à la promotion. Mais peut-être voulons-nous procéder à une vérification plus complexe , qui permettrait également
de vérifier les informations concernant le client. Bien entendu, nous pourrions
étendre l'énoncé if de plus en plus
complexe à la condition. Mais il
serait également intéressant que l'envoi promotions
par e-mail puisse bénéficier un mécanisme permettant de vérifier l'éligibilité en
appelant une autre fonction. Et c'est ce que nous pouvons faire
avec des fonctions d'ordre supérieur. Donc, ce que nous pouvons faire à la place, c'est
définir qu'une fonction est éligible à une promotion ET fonction va
attirer un client. Et il va
renvoyer un booléen. Et cela indiquera simplement au
client que le point h est supérieur à 50. Comment utilisons-nous cette
fonction ici ? Eh bien, on peut simplement
l'appeler, non ? Nous pouvons le faire s'il est
éligible à la promotion. Un client, comme ça. Ensuite, lorsque nous
exécuterons ceci et ce, nous obtiendrons
exactement les mêmes résultats. Mais cela nous donne encore très peu de contrôle, car il est désormais impossible définir d'autres fonctions
et de
déterminer ensuite de manière dynamique si nous devons envoyer un e-mail aux clients ou non. C'est toujours une fonction
spécifique au disque. Ainsi, au lieu de
l'appeler directement ici, nous pouvons également le transmettre comme argument pour envoyer
une promotion
par e-mail. Supposons donc
que la fonction soit éligible pour l'écrire
correctement. Évidemment, puisqu'il s'
agit d'une fonction, nous nous attendons à quelque chose de
type goal, c'est une fonction. Et comment spécifier quel
type de maladie fonctionnelle ? Eh bien, nous utilisons
les crochets puis nous utilisons une autre paire de crochets pour indiquer quels sont
les arguments
de cette fonction avec les types de paramètres. Donc, ce que cette expression est un client et ce qu'
elle renvoie sont booléens. Et puis, au lieu d' appeler le dysfonctionnement
directement ici, nous appelons la fonction que nous
transmettons en paramètre de la manière suivante. Et maintenant, bien sûr, nous devons nous
assurer que lorsque nous appelons
réellement la fonction ici, vous voyez qu'il y a également une erreur
que nous transmettons. Cette fonction particulière est éligible à la promotion. Comme ça. Maintenant, lorsque nous l'
exécutons, nous obtenons exactement le même résultat, mais maintenant nous l'avons
fait, en le répartissant un peu différemment, et maintenant nous utilisons fonctions
d'
ordre supérieur afin de séparer la fonction de promotion par e-mail et
la fonction de vérification d'éligibilité. Maintenant, au lieu d'avoir à
définir une fonction comme celle-ci
, vous pouvez également utiliser une fonction
lambda. La fonction Lambda en Python
est une fonction anonyme. Nous n'avons donc pas ici fonction
anonyme car
cette fonction a un nom. La fonction Lambda n'a pas
de nom et vous spécifiez directement
sous forme d'expression. Ainsi, au lieu d'avoir
cette fonction ici, à
laquelle nous faisons référence par son nom, nous pouvons utiliser une
fonction lambda. Cela va attirer un client et cela va renvoyer c, H est au moins 50. Et maintenant, lorsque nous exécutons
cela, nous obtenons à nouveau
exactement le même résultat. Mais maintenant, nous utilisons une fonction lambda
anonyme. Et c'est bien
parce que nous avons maintenant moyen
très simple de modifier la façon dont les
promotions par e-mail sont traitées avec le code
d'erreur. Par exemple, nous pouvons également modifier l'âge, disons seulement au-dessus de 60 ans. Et maintenant, nous allons
obtenir un résultat différent. Et nous n'avons rien eu
à modifier dans la fonction de
promotion « Envoyer un e-mail », qui est vraiment sympa.
10. Fonctions de premier niveau 2/4: Faisons en sorte que cet exemple
soit un peu plus compliqué. Je vais à nouveau supprimer la fonction
Lambda, et je vais appeler est éligible une
fois de plus. Je vais vous
montrer un autre moyen mieux contrôler ce qui se passe
lorsque vous appelez une fonction. Bien entendu, si nous sommes éligibles à une promotion, éligibles à une promotion, nous n'avons aucun moyen de contrôler
réellement cette valeur, car elle est
codée en dur dans la fonction. Nous pourrions donc
avoir la possibilité d'avoir un âge limite, qui sera un entier. Et puis au lieu d'
utiliser les 50 ans, nous pouvons utiliser la croix de
huit, n'est-ce pas ? Donc c'est vraiment sympa. Mais nous avons maintenant un
problème éligible à la promotion. Bien entendu, cela ne correspond plus
au type de
crédulité que nous avions ici. Et c'est parce qu'il y a maintenant ce paramètre supplémentaire
que nous devons fournir. Vous pouvez faire une
chose, par exemple fournir une valeur par défaut. Et puis c'est
une sorte de solution de contournement, car
maintenant cela fonctionne à nouveau. Mais maintenant, il n'y a toujours aucun
moyen de modifier l'âge ici de quelque manière que ce soit, car nous ne pouvons utiliser que la valeur
par défaut, n'est-ce pas ? Maintenant, c'est là que le package funk
tools peut
nous fournir une solution intéressante
appelée application à
fonctions partielles. Que signifie l'
application Parcel Function ? Cela signifie essentiellement que si
vous avez une fonction avec deux paramètres différents
comme celle que nous avons ici, c'est-à-dire qu'avec partial, vous pouvez déjà appliquer certains
de ces arguments. Et puis tu retrouves
une autre fonction. Lorsque vous appelez cette fonction, les arguments
que vous avez appliqués précédemment seront utilisés. Cela vous permet donc de modifier la
signature de l'en-tête de la fonction en fournissant
déjà certaines valeurs. Donc, par exemple ce que nous pouvons faire ici, c'est d'
abord importer à partir d'outils, qui est le modèle que
nous allons utiliser. Ensuite, ce que vous pouvez faire,
c'est supprimer à nouveau cette
valeur par défaut, afin de supprimer l'erreur. Vous pouvez maintenant dire,
eh bien, nous l'avons fait, est éligible. Et supposons que nous voulions couper
à 60 ans,
donc nous allons dire que
c'est éligible à 60 ans, ce qui est une demande partielle d'éligibilité à une promotion. Mais nous allons
lui fournir un âge limite de 60 ans. Et maintenant, lorsque nous avons envoyé une promotion
par e-mail, nous pouvons l'envoyer, nous pouvons lui fournir les 60 fonctions partiellement
appliquées éligibles. Donc, partial obtient une fonction. Elle applique une valeur à l'un de ses arguments et
renvoie une nouvelle fonction
, désormais appelée
is eligible 60. Malheureusement, nous
ne savons pas exactement quel
est le type de cette fonction partiellement
appliquée. Peut-être dans une future version
de Python,
mais il s'agit à nouveau d'une fonction qui est maintenant appelée par des promotions envoyées par e-mail. Quand je l'exécuterai,
vous aurez
des clients âgés de
plus de 60 ans. Il s'agit donc d'un exemple d' application à fonctions
partielles
vraiment puissante qui vous permet de modifier des fonctions, les
simplifier et de les utiliser, les
rendre compatibles
avec d'autres domaines de votre application en
appliquant déjà certaines des valeurs.
11. Fonctions de niveau 3/4: Une autre bonne chose que vous
pouvez faire avec les outils func est ce que l'on appelle la propriété en cache. Vous vous souvenez peut-être de l'exemple que
je vous ai montré dans
l'une des leçons précédentes où j'avais une personne et nous avions une propriété de chaîne de
recherche, qui était une propriété
calculée. Ainsi, chaque fois que vous
appelez la propriété, la valeur est informatique. est peut-être pas toujours ce que vous voulez si la valeur
doit calculer trois, complexe à calculer,
eh bien, avec la
chaîne de recherche, ce n'était pas si mal. Mais si c'est vraiment complexe,
vous voulez éviter d'avoir à
le calculer à chaque fois que
vous appelez la propriété. Une façon de le résoudre
est de stocker la valeur dans l'objet que vous avez calculé lorsque vous
créez l'objet. Mais si vous utilisez une classe de données figée,
cela n'est pas possible. C'est là que les propriétés mises en cache entrent en jeu à partir des fonctions. Voici donc un exemple
de la façon dont il est utilisé. J'ai un ensemble de données de classe qui
contient une séquence de nombres. Et dans ce cas, je le stocke
simplement sous forme de tuple dans une variable d'instance de données. Et puis j'ai la trésorerie, qui correspond à l'écart type
de ces données particulières. Et j'utilise la fonction d'
écart type à partir des statistiques. Et puis après
la fonction principale où
crée essentiellement une instance
de cet ensemble de données. Ensuite, j'imprime
l'écart type. Et ce qui est vraiment intéressant, c'est que si je le lance maintenant, vous verrez que nous n'obtenons qu'
une fois le
message qui calcule l'
écart type. Et c'est parce que
cela est mis en cache. La propriété est calculée
une fois et chaque fois que vous appelez ensuite, elle
utilise simplement la valeur mise en cache. C'est donc vraiment puissant si je devais utiliser une
propriété normale pour cela. Comme ça. Et maintenant,
je le répète, vous voyez que l'
écart type est calculé trois fois. C'est ce qui fait la différence.
Je vais donc transformer cette véritable propriété en espèces. Et maintenant, lorsque nous l'exécutons à nouveau, il n'est à nouveau calculé qu'une seule fois. Vous utilisez donc une
propriété monétaire pour mémoriser certaine valeur.
Vous n'avez donc pas à les
calculer encore
et encore, tout en ayant la
possibilité d'y
accéder comme une
propriété normale dans votre objet.
12. Fonctions de niveau 4/4: dernière chose cool
que je veux vous montrer depuis Fontanelles, c'est une dépêche unique. Single Dispatch est un
décorateur que vous pouvez utiliser pour surcharger une sorte de
fonction. Vous définissez donc une fonction générique
et enregistrez des variétés de cette fonction
qui peuvent gérer différents types. Voici un exemple. J'ai une seule fonction de répartition appelée add qui a un x et un y, deux entiers, et qui renvoie
la somme de deux entiers. Mais j'ajoute ensuite une deuxième
version de cette fonction. Il s'agit donc, disons, de
la version par défaut de la fonction
qui obtient des entiers. Le second qui reçoit
des chaînes et des chaînes. Je ne veux pas les ajouter
directement comme ça. Je souhaite ajouter un espace. J'utilise donc la
mise en forme de chaîne ici pour insérer un espace entre
le x et le y. J'y
reviendrai dans une minute, mais si nous avons ici imprimé 12 et imprimons Hello World, alors vous verrez que la
première ligne indiquant qu'elle
va imprimer est bien la somme et les chaînes concaténées avec l'
espace entre elles. Et il y a d'autres choses que vous pouvez faire avec ça. Vous pouvez par exemple également utiliser le type d'union dont j'ai parlé dans
la vidéo de saisie. J'enregistre donc ici une version de cette fonction qui
prend un x et un y, c'est soit une liste, soit un ensemble. Et cela renvoie une liste, enchaînant
simplement les éléments
de la liste des ensembles. Et il existe également une forme
fonctionnelle. Ceux-ci utilisent donc un soi-disant décorateur avec
le signe d'ajout devant celui-ci. Mais vous pouvez aussi simplement
appeler le registre par points en tant que fonction et vous fournissez le type , puis la fonction qui
doit le gérer. C'est donc ce que vous
voyez se faire ici. Je peux donc simplement réexécuter cette liste
et celle de l'OCDE à renvoyer. Et le dernier renvoie un tuple parce que c'est ce que nous avons
spécifié ici. Émettez un tuple plus rapide, puis vous
renvoyez également un tuple. Vous pouvez donc utiliser une
répartition unique pour gérer facilement des
objets de différents
types en Python. Pour être honnête, je ne l'ai pas beaucoup
utilisé, mais je pense qu'il est utile de
savoir que cela existe. Et dans certains cas, il peut être utile
de simplifier un peu votre code. Donc, dans l'ensemble, je pense que
la bibliothèque d'outils funk est une
collection d'outils vraiment intéressante. Il y a aussi quelques autres
choses qui
n'ont pas été abordées dans cette
leçon d'aujourd'hui. Vous pouvez consulter
la documentation. Mais dans l'ensemble, je pense que
c'est vraiment intéressant. Comme j'ai également
remarqué, beaucoup de gens ont tendance
à s'en tenir aux cours, alors que les fonctions sont également
très puissantes. Par conséquent, ils vous
permettent également souvent de simplifier votre code au lieu d'
utiliser des classes partout. La prochaine fois que vous écrirez un programme Python, vous aurez affaire à des
classes complexes et à tout le reste. Réfléchissez à la façon dont
vous pouvez
en faire une version plus fonctionnelle. Et vous remarquerez souvent
que le code sera plus court et plus facile à lire. Ce sont donc des outils amusants et une sorte de
programmation fonctionnelle en Python. leçon suivante, je
vais jeter un œil à autre concept que vous
voulez trouver vraiment utile,
à savoir programmation concurrente.
13. Programmation simultanée 1/3: Surtout si vous commencez à utiliser Python de manière plus professionnelle, vous allez soudainement
interagir avec une API,
une base de données, etc.,
essentiellement via un réseau. Et si vous le faites,
cela signifie qu'il devient important
pour votre application de
traiter efficacement ces types de
demandes. Parce que si vous ne le faites pas,
votre application sera très lente. En Python, vous pouvez utiliser le package d'E/S asynchrone
pour vous aider. Et cela repose sur ce que l' on appelle la programmation
concurrente. Vous avez peut-être déjà entendu le terme simultanéité de programmation
concurrente et le
terme apparenté parallélisme, programmation
parallèle. Ces choses ne sont en fait
pas la même chose. Il y en a différents.
La différence réside dans le fait que le
calcul parallèle signifie que vous disposez
en fait d'unités de traitement
parallèles distinctes pour effectuer des tâches distinctes. Donc, si vous avez une
application qui fait plusieurs choses
en même temps, ces tâches sont
en fait effectuées en parallèle en même temps. C'est du parallélisme
et la
simultanéité signifie qu'une application
progresse sur plusieurs
tâches en même temps. Mais au lieu d'avoir de
véritables opérations parallèles, il va en fait basculer dynamiquement
entre ces tâches. Disons qu'une application
va de la tâche A à la tâche B, elle va simplement commencer à faire un
peu d'une opération
continue avec a, continuer avec B, un bit de B, puis revenir à a et
ainsi de suite. Ce n'est donc pas parallèle, mais il s'agit
simplement de passer de l'un à l'autre. Parce que ça va très vite. En tant qu'utilisateur, vous pouvez avoir l'idée que cela
se produit en parallèle, mais en réalité, cela
se produit simultanément. Il s'agit simplement de changer. C'est comme la différence entre les files d'attente parallèles devant un
caissier. Cela signifie que nous avons
plusieurs caissiers et chaque caissier a une ligne
qu'il traite. La simultanéité signifie qu'
il n'y a qu'un seul caissier, mais qu'il y a plusieurs files d'attente et que tout le monde se relaie. Dans ce cas, les files d'attente
correspondent aux tâches qu' un ordinateur doit résoudre et
les caissiers sont les processeurs. Les ordinateurs modernes
utilisent une combinaison de parallélisme et de simultanéité. Vous savez, votre processeur peut avoir 246810 cœurs qui peuvent tous
faire des choses en parallèle, mais votre système d'exploitation aura des dizaines, voire des centaines de tâches
différentes. Et il va
exécuter un sous-ensemble de ces tâches en parallèle sur
ces différents cœurs de processeur, mais il va également
basculer entre
elles simultanément. parallélisme en Python
comporte une mise en garde en ce que Python possède ce que l'on appelle un verrou d'interpréteur
global. Cela signifie que si
vous avez, disons, plusieurs threads
censés être parallèles,
qui pourraient l'être en fait
en Python, cela ne fonctionne pas
car ils sont verrouillés sur l'interpréteur. Il y a des raisons à cela. Je n'aborderai pas cela
dans cette leçon. Mais
les conséquences du parallélisme en Python ne sont pas
vraiment possibles. Il existe quelques solutions de
contournement, par exemple vous pourriez, au lieu d'
avoir un seul processus, utiliser le
backedge multitraitement pour créer
plusieurs processus. Et Dan, tu
as du parallélisme. Vous pouvez également passer à un autre
interpréteur Python qui ne possède pas ce verrou d'
interpréteur global. Mais en réalité, il
n'y a pas beaucoup de cas où vous avez
besoin du parallélisme. Souvent, la
simultanéité est déjà très bonne et Python prend très bien en
charge la concurrence,
en particulier depuis Python 3.7,
qui a en particulier depuis Python 3.7, considérablement amélioré le package
Async IO. La simultanéité est désormais très
importante car elle vous
permet d'avoir
plusieurs tâches, par exemple une tâche pour récupérer
des données à partir d'une API. En attendant
la réponse de l'API,
vous pouvez déjà passer
à une autre tâche, ce qui est également utile, par exemple si vous avez une application graphique
et que l'interface graphique attend que vous
saisissiez du texte dans les
champs de texte ou que vous appuyiez sur un bouton. Eh bien, comme il s'agit d'un programme
simultané, vous pouvez effectuer d'autres tâches
en même temps, comme nettoyer une
partie de la mémoire, préextraire
des données ou faire tout ce que vous voulez pour améliorer le fonctionnement de l'application
. Et étant donné que presque
toutes les applications
communiquent aujourd'hui sur Internet et récupèrent un tas de données. Il est très important gérer correctement la concurrence. Et c'est ce que le package
Async IO de Python vous permet de faire.
14. Programmation simultanée 2/3: Il existe deux
mots clés importants que vous devez connaître si vous écrivez du code simultané ou
asynchrone, l'attente asynchrone. Vous pouvez écrire une fonction asynchrone
devant une fonction ou une
méthode pour indiquer qu'il
s'agira d'une fonction ou d'une méthode que vous pouvez
appeler simultanément. Vous pouvez également utiliser une pondération pour indiquer
devant une déclaration que la déclaration
suivante doit
attendre la fin de la
déclaration précédente. Et c'est la
deuxième partie qui est également très utile car vous
devez souvent attendre
une certaine réponse
pour faire quelque chose. Par exemple, si vous récupérez
des données à partir d'une API, vous devez attendre de récupérer deux données pour pouvoir réellement faire
quelque chose avec ces données. Async et wait ont donc un exemple
très simple ici. Vous pouvez voir que nous
avons une fonction obtient Pokémon qui utilise l'
API Pokemon pour obtenir les noms des Pokémon. Et nous transmettons, dans
ce cas, un identifiant et nous
avons une URL à laquelle
nous fournissons l'identifiant. C'est ainsi que nous
devons appeler cette API. Et puis je reviens en
attendant HTTP GET. Et puis l'URL http get est une fonction d'assistance
que j'ai créée. C'est asynchrone. Je vais vous montrer comment cela
fonctionne dans une minute. Mais ici, nous voyons la fonction
asynchrone Get Pokemon qui
renvoie les poids, puis récupère
les données de l'URL. Et nous faisons appel à un serveur
car, bien entendu, nous
ne pouvons revenir qu'une fois que
nous avons ces données. La fonction principale ici, comme vous pouvez le voir ici, est également asynchrone car, eh bien, elle utilise la
fonction rent int pour créer un entier aléatoire entre un
et l'identifiant Pokemon le plus élevé, qui est actuellement 898. Ensuite, j'utilise un poids pour obtenir le Pokémon à partir de
cet identifiant en particulier, puis j'imprime le
nom du Pokémon. Et ici, le poids est également très important car,
bien sûr, je dois
attendre d'avoir la valeur Pokemon pour pouvoir imprimer le nom. C'est ce que vous voyez ici. J'ai contourné ça. Vous voyez, nous obtenons des Pokémon au hasard
et vous constatez qu'il a fallu environ une
demi-seconde ou une seconde pour obtenir cette
valeur Pokémon particulière. Essayons encore une fois. Vous voyez, cela prend un certain temps
, puis nous obtenons le résultat. C'est faux car
nous devons attendre que l'API nous
réponde, ce qui peut prendre un certain temps. Voici un autre
exemple qui montre à quel point il est
utile d'utiliser la programmation
concurrente. Donc, ce que j'ai fait ici, c'est que j'ai
deux versions pour le faire. Recevez une demande depuis l'API. J'ai une version asynchrone et une version
synchrone. Vous avez ici une fonction qui utilise la version synchrone. Donc, ce que je fais, c'est que je reçois Pokemon à partir de
cette URL particulière. Et ici, je n'ai pas de version
asynchrone qui contient ce Pokémon. Et dans ce cas, j'utilise la fonction
HTTP GET asynchrone. Dans ma fonction principale, j'ai alors deux versions
après des appels synchrones. Donc, en gros, cela pondère
à chaque fois les résultats, n'est-ce pas ? Je fais donc une boucle et j'
obtiens 20 noms locaux aléatoires, puis je calcule
le temps total. Et dans l'appel asynchrone, j'utilise quelque chose appelé
Async IO dot gather. Et cela me
permet de lui fournir un certain nombre d' appels et
un certain nombre d'appels asynchrones, puis il les lancera, ils veulent
toujours des fourmis au lieu d'attendre la
fin de chaque mois avant de commencer
le suivant collecte
asynchrone d'aorte nous permet exécuter toutes ces choses
simultanément. Donc, lorsque vous exécutez ceci, vous le voyez alors que c'
est la première fois. Vous avez donc vu que dans
le cas synchrone, il nous a fallu près de 2 s
pour
obtenir ces 20 noms de Pokémon ,
car nous attendons le premier avant de demander
le second. Et dans le cas asynchrone, cela n'a pris que 0,9 s, soit moins de la moitié. Et c'est parce que nous
gérons les choses simultanément. Nous n'avons pas besoin d'attendre les résultats du
premier appel d'API. Pour lancer le deuxième appel d'API, il faut
faire attention, à savoir que ces
API ont souvent des limites de RAID. Vous ne voulez donc pas
lancer 1 000 appels d'
API ou ne le souhaitez pas, car
cela ne sera pas accepté. Vous devez donc effectuer la demande d'API dans
certaines limites de débit, exemple un nombre fixe d'appels, comme le nombre maximum
d'appels par seconde, dépend de l'API qui
doit le rechercher. Mais comme vous pouvez le constater
en réfléchissant un peu façon dont nous pouvons exécuter notre
code de manière asynchrone, façon dont il peut s'exécuter simultanément. Cela va nous faire économiser
beaucoup de temps d'attente et
rendre notre application beaucoup plus fluide. C'est donc rassemblé, rassemblé
En gros, ce que vous voyez ici, je déballe une liste de différents appels de
fonctions asynchrones. C'est donc async io.gov, qui est un outil vraiment utile
pour exécuter des choses simultanément. Et tout ce que l'on peut voir ici dans ces exemples, c'est que nous avons cette fonction principale asynchrone, mais que nous l'exécutons en utilisant un système de points d'E/S
asynchrone, qui indique à l'
interpréteur Python d'exécuter cette fonction principale de
manière asynchrone. Et nous en avons besoin, car
si j'écris simplement principal, cela ne
fonctionnera pas comme prévu. Parce que si je fais fonctionner cette climatisation, nous recevons toutes
sortes d'avertissements indiquant que la co-routine du Maine
était de ne jamais l'attendre. Et c'est exactement ce qui se passe ici, bien sûr
. Nous l'appelons simplement. Donc, si vous voulez
éviter cela, vous
devez appeler async IO point run et l'écrire correctement, bien
sûr, doctrine. Et puis nous appelons la fonction
principale ainsi. Quand je l'exécute
à nouveau, vous voyez
que nous n'avons plus l'
erreur.
15. Programmation simultanée 3/3: La dernière chose que je
veux vous montrer est
comment transformer du code synchrone non concurrent en code
qui s'exécute simultanément. Et cela peut arriver
parfois. Vous
utilisez peut-être un package de bibliothèque qui n'est pas asynchrone, mais que vous souhaitez le
transformer en appel asynchrone. Comment faites-vous cela ? J'ai donc un exemple ici. Il y a donc une
fonction asynchrone ici, un compteur, et il y a aussi une fonction d'envoi
synchrone de
demandes ici. Et cela consiste simplement
à utiliser le package de requêtes d'
écriture, le package de requêtes n'est pas
réellement asynchrone
et synchrone. Cela signifie que si nous
envoyons une demande ici, nous devons attendre le résultat et simplement renvoyer
le code d'état. Dans ce cas,
ma fonction principale est ici et j'envoie une demande
à our alcohols are gone, qui est mon site Web. Et puis j'imprime
la réponse HTTP avec cet état, puis
j'appelle le compteur. Une autre question est, bien entendu, pourquoi devrions-nous attendre la réponse ici
pour démarrer le compteur ? C'est tout J'en ai besoin, non ? Donc, si je lance ceci, vous voyez
que nous envoyons la demande, puis nous avons la réponse, puis nous commençons à contrer. Et si nous voulions
utiliser Gathered pour démarrer un compteur en même temps
que l'envoi de la demande. Comment faisons-nous cela ? Eh bien,
si nous voulons le faire, cela signifie que nous devons activer l'
envoi de la demande, etc. Fonction concurrente asynchrone au lieu d'une fonction synchrone, si vous voulez le faire, c'
est en fait très simple. Donc, au lieu d'appeler des demandes d'
envoi comme celle-ci, vous pouvez utiliser des E/S
asynchrones à deux points. Est-ce que cela va en
faire un fil de discussion ? Ensuite, nous
appelons Send Request. Nous devons également fournir les
arguments, à savoir l'URL. Ensuite, nous devons écrire un
poids devant, car toute menace transforme cette fonction
en fonction asynchrone. Alors laissez-moi exécuter ceci et vous verrez que nous obtenons toujours
exactement le même résultat, n'est-ce pas ? Parce que nous n'avons aucun poids. Nous envoyons donc la demande, obtenons la réponse, puis
nous démarrons le compteur. Mais maintenant que nous avons la version
asynchrone, nous pouvons en fait utiliser
asynchrony all dot gather pour faire ces deux
choses en même temps. Nous avons donc ici un exemple
où j'ai configuré cela. Donc, ce que j'ai fait,
c'est créer une autre fonction appelée requête asynchrone
envoyée qui utilise un point d'E/S asynchrone pour menacer d'appeler
celui-ci de manière asynchrone. Et puis, dans ma fonction principale, je n'ai pas de collecte de points d'E/S asynchrone. Et puis j'ai envoyé
la requête
asynchrone qui cause un dysfonctionnement, qui menace de transformer cela en une fonction
asynchrone. Et j'utilise aussi un compteur. Et quand je l'exécuterai, vous verrez que
nous avons le compteur. Et cela commence en même
temps que l'envoi d'une demande. Ensuite, nous attendons et, à la
fin, nous obtenons la réponse. C'est donc une E/S asynchrone. Enfin, voici notre équipe asynchrone Get Pokemon
qui utilisait cette fonction HTTP GET, une
fonction d'assistance que j'ai créée. C'est en fait dans ce dossier. Et vous voyez que nous utilisons ici le
thread
Async IO point two pour transformer la
fonction request point gets en un appel de fonction
asynchrone. Cela utilise donc exactement
le même mécanisme pour conclure que les E/S asynchrones sont une fonctionnalité très
puissante de Python. programmation simultanée est
généralement très utile, en particulier si vous
communiquez via un réseau avec d'autres services et que vous souhaitez que votre application
fonctionne correctement. J'espère donc que cette leçon vous a donné quelques idées sur la façon dont vous pouvez transformer
votre propre code
en code asynchrone, particulier si vous
effectuez une grande partie de
cette
communication avec une API ou une base de données. Dans les quelques
leçons restantes de ce cours, il peut
que je fasse parfois référence
à la programmation simultanée. Montrez comment vous pouvez utiliser
cette fonctionnalité en particulier, en tenant compte
de la programmation simultanée. Maintenant, la prochaine leçon
portera sur les itérateurs.
16. Iterators 1/3: Dans cette leçon,
je vais
parler des itérateurs en Python. Ce qui n'est pas un itérateur
Bien qu'il s'agisse essentiellement d'un objet qui peut
être itéré, vous pouvez
parcourir toutes les valeurs. Vous pouvez reconnaître un
itérateur en Python car il implémente
le protocole d'itération, ce qui signifie qu'il possède
les méthodes domino suivantes. itérateurs sont
omniprésents en Python, ils sont utilisés dans les boucles, ils utilisent la compréhension de listes et bien d'autres endroits où
vous
les avez probablement déjà utilisés plusieurs fois sans même rendre compte qu'il s'
agissait d'itérateurs. Vous avez peut-être entendu
les termes
itérateur et itérable. Ce n'est pas la même chose. Un objet itérable qui peut vous
fournir un itérateur. Cela signifie qu'il utilise la méthode itr dunder car
cela vous donne un itérateur. Un itérateur situé à côté de la méthode donatrice
itr possède également une méthode dominante suivante
qui nous permet d' obtenir l'élément suivant
de l'itération. Certains de ces itérateurs
sont limités, par exemple vous pouvez parcourir
une liste fixe d'éléments. Certains de ces itérateurs
sont infinis. Par exemple, vous pouvez itérer sur
toutes les valeurs entières. Bien entendu, en Python, il
n'y a pas de valeur maximale pour un entier, moins quelques points indiquant que la mémoire de votre
ordinateur est limitée. Donc, les listes, les tuples,
les dictionnaires, les ensembles, chaînes, ce sont des choses
qui sont toutes itérables. Et vous pouvez obtenir un itérateur
à partir d'eux, puis vous pouvez itérer sur la séquence
en question. Jetons un coup d'
œil à quelques exemples. J'ai une fonction principale ici, et il y a un élément de classe qui porte un nom et un poids
. Chaque élément a un poids. J'utilise évidemment des
classes de données. Et puis après
la fonction principale, n'importe où, la liste des objets et j'appelle
cela un inventaire. Maintenant, ce que je peux faire, c'est que l'
inventaire est une liste, donc c'est un itérable. Je peux donc en obtenir un
itérateur. Je peux donc faire un inventaire. L'itérateur est égal à
Inventory Dot Dr Hitter. Cela va me donner l'itérateur, puis
je pourrai imprimer, par exemple itérateur
d'inventaire point,
puis Dahmer ensuite. C'est donc en utilisant le protocole
d'itération. Si je l'exécute, vous
verrez qu'il va imprimer le premier élément de
cette séquence itérative. Si je copie cette ligne, comme ça, elle appellera Max
deux fois et elle
passera au deuxième élément. C'est ce que vous voyez ici. Il existe un moyen légèrement
plus simple de procéder au lieu d'appeler
ces méthodes inutiles Nous pouvons également
faire
ce qu'il faut. C'est elle, qui est une fonction auxiliaire qui
désigne simplement la
méthode dominante pour nous. De même, nous
pouvons également utiliser next, qui désigne la prochaine
méthode dominante pour nous. Comme ça. Et maintenant, nous obtenons exactement
le même résultat. Je peux donc continuer à
le faire. Il y a donc six articles ici. Je vais donc maintenant imprimer tous les éléments
de cette liste
particulière. Alors, que se passera-t-il si
j'en ajoute un de plus ? Eh bien, cela va provoquer une erreur
d'arrêt de l'itération. Vous voyez donc que nous
arrivons ici à un retraçage, il y a un arrêt de l'itération. C'est ainsi qu'un
itérateur indique : « Hé, il n'y en a plus, je peux vous donner autre
chose.
Maintenant, vous pouvez, par exemple créer une boucle while,
puis insérer une instruction try except, puis récupérer ces
itérations d'arrêt, puis, vous savez, vous êtes stupide. Mais bien sûr, personne n'
utilise les itérateurs de cette manière. Ce n'est pas une façon beaucoup
plus simple de le faire, et c'est simplement
en utilisant une boucle for. Permettez-moi donc
de supprimer toutes ces choses ici. Ensuite, je vais écrire
pour l'article en inventaire. Ensuite, je
vais simplement imprimer le point-virgule de l'article, en fait. Nous y entrons et
imprimons simplement tous les articles. En fait, la boucle for
utilise la méthode iter et la méthode next. Elle reçoit
donc d'abord un
itérateur, puis elle appelle next plusieurs fois jusqu'à ce qu'elle rencontre
l'erreur
d' arrêt de l'itération,
puis elle s'arrête. C'est ce que
fait la boucle for. Rien d'autre. avantage de la fonction
iter qui appelle la méthode donateur, c'est
que vous pouvez également lui
fournir une valeur sentinelle. Et c'est essentiellement une valeur
qui doit être fournie pour indiquer la fin
de l'itérateur. Ceci est utile, par exemple,
si vous lisez des données à partir d'un fichier ou d'un réseau, essentiellement un flux de
données et que vous souhaitez savoir si la fin du
flux a été atteinte. J'ai donc un exemple ici. Il s'agit donc d'un fichier appelé country's qui contient
quelques pays. Ensuite, je peux utiliser la valeur sentinelle pour indiquer la
fin du fichier. Je peux donc utiliser une instruction de largeur. C'est un gestionnaire de contexte. J'en parlerai
dans une prochaine leçon. Et je vais utiliser Open,
puis je vais ouvrir le fichier TXT à points des
pays. Et puis je fais la
queue dans une entrée amusante. Et puis il va
appeler la ligne de lecture phi point, qui renvoie un itérable. Et la valeur sentinelle
sera la chaîne vide. Ensuite, je vais
imprimer la ligne. Donc, lorsque nous faisons
cela, vous voyez que nous obtenons tous
ces pays. Et comme le fichier texte contient
déjà de nouvelles lignes, je peux simplement les supprimer
de l'instruction print en indiquant que la fin de l'instruction print
est une chaîne vide. Ensuite, ça va
être un peu plus beau. La chaîne vide
ici est donc utilisée
comme valeur sentinelle pour indiquer que nous atteignons
la fin du fichier.
17. Iterators 2/3: Comme nous avons ces
itérables et itérateurs, ils nous permettent également d'
introduire une certaine abstraction. Voici donc un autre exemple. Voici donc une classe d'articles. C'est une classe de données figée. J'en ai parlé au
début du cours. Et chaque article a
un prix et une quantité. C'est le prix total, ça renvoie un entier, et c'est simplement le prix
multiplié par la quantité. Et puis la fonction f for imprime
les totaux qui obtiennent des éléments. Et je vois que je
ne lui transmets pas une liste de rubriques et que je lui transmets un itérable de
lignes et de principes. La seule chose que je
ferais, c'est qu'
en utilisant la boucle pour les objets et un prince, le prix total de
ma fonction principale, j'ai une liste de rubriques. Regardez ça ici, puis
je vais appeler les totaux imprimés. Donc, lorsque je l'exécute,
il
imprime simplement tous les totaux. Mais ce qui est bien
maintenant, c'est que Print Totals attend
quelque chose d'itérable, peu importe qu'il s'agisse d'une liste, d'un tuple
ou de quoi que ce soit d'autre. Donc, par exemple, ici, si mes éléments de
ligne sont listés, je peux les remplacer
par un tuple, comme ceci. Maintenant, ce n'est plus une liste, mais l'impression des totaux ne compte pas. Tant qu'il est itérable, il peut faire son travail. Les itérateurs
vous permettent donc d'introduire également une certaine abstraction, car Imprime Altos ne se soucie pas de
la structure des données. Il se soucie simplement d'
avoir quelque chose sur lequel il peut itérer et
c'est tout ce dont il a besoin.
18. Iterators 3/3: Si vous voulez vraiment faire
passer
les itérateurs au niveau supérieur, vous pouvez également utiliser les outils GitHub, qui sont un package, package
standard
de Python doté de mécanismes d'
itération
très puissants. C'est une sorte d'
algèbre d'itérations. Comme vous pouvez le faire, tous ces
itérateurs, combinez-les de
différentes manières pour obtenir un comportement
vraiment complexe. Supposons par exemple que vous vouliez d'abord filtrer les éléments
d'une liste, puis multiplier ces éléments
par une autre valeur d'une autre liste, puis les
enchaîner avec un autre ensemble de valeurs. Vous utiliseriez
peut-être normalement une combinaison
de fonctions
et de boucles pour cela. Mais vous pouvez également utiliser d'autres outils pour combiner
ces opérations en une seule opération de grande envergure à
l'aide de l'algèbre itératrice. Je vais vous montrer quelques
exemples de la façon dont cela fonctionne. Donc, pour ne pas les utiliser, les
outils, bien sûr, il va falloir les
importer. Ça ira. Et puis il y a deux
choses que vous pouvez faire. Cela semble très simple,
mais il y a quelques choses
très avancées que vous
pouvez faire avec les itérateurs. Je vais donc recommencer avec ma liste d'inventaire, car elle sera
utile pour vous montrer
ce que vous pouvez faire avec les itérateurs. Je vais simplement supprimer
ces lignes ici. Eh bien, commençons par
quelque chose de très simple. Un
exemple très simple est count, une fonction
d'itertools qui vous
permet de compter à
partir d'un certain nombre. Nous pouvons donc utiliser une boucle car
c'est un itérable, n'est-ce pas ? Nous avons des dénombrements et nous pouvons ensuite indiquer, par exemple, le point
de départ. Nous voulons donc commencer à
compter à dix. Et vous pouvez même
indiquer une étape, par exemple avec des étapes de cinq et imprimer I. Maintenant, si je m'arrête ici, cela se
poursuivra essentiellement indéfiniment. Donc, si le chi est égal, disons à 50, alors
nous allons faire une pause. Donc, quand je lance ça, c'est ce que tu obtiens. C'est donc la
fonction count, counts Iterable. répétition n'est pas un exemple simple. Alors maintenant, cela va
se répéter 105 fois. Exécutons ceci et vous verrez
que c'est exactement
ce qui se passe. Une autre chose que vous
pouvez faire est d'accumuler, ce qui permet de calculer les sommes partielles. Supposons donc que nous ayons des sous-totaux
, soit, disons, une
liste de quelques nombres. Je tape juste des
choses au hasard ici, comme ça. Ensuite, ce que nous pouvons
faire, c'est utiliser accumuler. Et nous allons
lui fournir la liste des sous-totaux. Mais vous pouvez également le fournir,
en gros n'importe quel autre itérable gros n'importe quel autre itérable
pour lequel vous pourriez
utiliser un autre It's Tools, des
fonctions, puis
je vais simplement imprimer I et ceci dont nous
n'avons pas besoin dans ce cas. Donc, ce que nous allons
faire maintenant, c'est parcourir cette liste de sous-totaux et à chaque fois calculer la somme
partielle, ainsi de suite. C'est ce que nous obtenons en conséquence. D'autres choses que vous pouvez en
faire s'installent. Disons que nous
avons des cartes à jouer, qui sont une liste,
disons, de chaînes de caractères. J'utilise le
copilote GitHub ici pour le
générer pour
moi afin de ne pas l'avoir saisi. Mais maintenant, vous
pouvez utiliser des permutations. Les permutations fonctionnent. Ce sont les outils
de toutes ces cartes à jouer. Et disons que nous voulons avoir
toutes les permutations de, c'est tout pour les cartes à jouer. Et ensuite, imprimons-les. Comme les fermentations se
situent à nouveau sur son ribosome, vous pouvez utiliser une boucle for pour
itérer dessus. Ils vont partir. Et quand on lance ça, eh bien, c'est ce que l'on obtient. Nous avons donc maintenant toutes les combinaisons
possibles de quatre cartes à jouer différentes. Et simplifions-nous un
peu les choses pour qu' il soit un peu plus facile de
voir ce qui se passe. Je vais donc simplement
créer un a, un B et un C. Supposons que nous voulions avoir
toutes les combinaisons de deux. Et puis c'est
ce que nous obtenons, non ? Vous voyez donc que l'ordre
est vraiment important ici. Donc AB est autre chose que ba, si l'ordre n'a pas d'importance, vous n'utilisez pas de permutations, mais vous utilisez des combinaisons, alors voici ce que nous obtenons. Bien sûr, il existe
beaucoup moins
de combinaisons de ces trois
caractères, AB, AC et BC, au lieu d'une
boucle pour imprimer chaque valeur, nous pouvons également utiliser autre chose. Nous pouvons utiliser l'initialiseur de liste
pour transformer les résultats de ces combinaisons itérables en une liste que nous pouvons
ensuite simplement imprimer et voici ce que nous obtenons. Il y a d'autres choses
que vous pouvez faire avec des outils, par exemple utiliser une chaîne. Donc, si nous
modifions les valeurs avec, disons, un analyste d ,
e, f, alors nous
obtiendrons une seule liste
qui est une chaîne de ces deux listes distinctes. Et bien sûr, vous pouvez transmettre
n'importe quel type d'itérable ici. Une autre chose qui est également
utile est le filtre faux. Vous pouvez donc imprimer,
disons, une liste de It's a
tool start, filter false. Et je veux
filtrer tous
les articles pesant moins de 1 kg. Je vais donc utiliser ici une fonction
lambda où x point wait pour écrire
correctement est inférieur à un. Et bien sûr, je vais lui
transmettre mon inventaire. Et puis il devrait y
avoir deux colonnes ici. Je pense que non, il ne
me manque aucune parenthèse. Donc, quand je lance ça, c'est ce que nous obtenons. Nous voyons donc que nous n'
avons que l'ordinateur portable, le livre et l'appareil photo, qui pèsent un kilo ou plus. Enfin, je veux vous
montrer une carte des étoiles, qui est une autre fonction d'itertools
qui vous permet de
prendre une liste ou un
itérable de tuples, dans ce cas de valeurs multiples. Ensuite, pour chaque valeur vous pouvez appliquer
une sorte d'opérations. Je suis donc en train de faire
une multiplication. J'ai donc une liste de tuples ici. Cela
va donc créer une nouvelle liste de deux fois 68 fois
4,5 fois trois. Et c'est le résultat
que vous voyez ici. C'est donc une carte des étoiles. Et maintenant, nous pouvons imaginer qu' avec ces deux fonctions, vous pouvez réellement combiner
les choses de différentes manières. Vous pouvez donc utiliser le filtre false pour créer un nouvel itérable avec un sous-ensemble d'
éléments et de liste. Et si vous utilisez les accumulations pour calculer le
poids total ou quelque chose comme ça, vous pouvez
utiliser la carte des étoiles pour calculer les temps d'attente , la
quantité, etc. Vous pouvez utiliser toutes ces
combinaisons pour créer une sorte d'algèbre qui
leur donne un comportement complexe. Et c'est une façon différente de
procéder que, disons, en utilisant des boucles ou en divisant des choses, des
fonctions et des choses comme ça. Et vous pouvez
bien sûr également créer vos propres itérateurs personnalisés qui répondent
à vos besoins pour les combiner
parfaitement avec itertools car tout suit
le protocole itérable. Voici donc un petit
exercice pour vous. Examinez votre code
précédent et voyez si
vous pouvez trouver des exemples dans lesquels vous pourriez, au lieu d'utiliser une
boucle for pour parcourir la liste, utiliser les outils pour effectuer
cette opération particulière. C'est vraiment amusant à faire et cela peut parfois conduire à un code
beaucoup plus court. Mais attention,
car si vous utilisez une
combinaison d'outils très complexe, elle sera également
très difficile à comprendre. Vous devez donc vous assurer que
votre code est toujours lisible. Et bien sûr, vous pouvez
toujours bien
diviser les choses en
différentes fonctions, même si vous combinez
différentes fonctions d'outils. Dans la leçon suivante,
je vais aborder les itérateurs
paresseux, également
appelés générateurs.
19. Générateurs 1/4: Dans cette leçon, je
vais parler générateurs et de certaines fonctionnalités spéciales en Python : les
données créent
ce que l' on appelle un itérateur paresseux et ceux-ci ont été introduits
et Pepper 255. Alors, que signifie réellement un
itérateur paresseux ? Eh bien, c'est presque la même chose qu' un itérateur normal, sauf
qu'il ne crée les valeurs que
lorsque vous les demandez. Donc, au lieu d'avoir, disons que vous avez
une liste avec des valeurs, vous définissez la liste avant
de pouvoir la parcourir. Vous devez donc créer
la liste complète. Avec un itérateur paresseux. Vous ne créez ces objets qu'au
fur et à mesure que vous les parcourez. Cela signifie donc que l'itérateur paresseux ne stocke pas son
concept en mémoire. Il crée le contenu à
la volée lorsque vous le demandez. Cela signifie que
dans certains cas, c'est une solution
plus appropriée que de tout calculer avance avant de commencer itérer. Elle
génère également un moyen simple de
créer des itérateurs, car
elle génère essentiellement une classe avec les méthodes iter et next
dunder sur lesquelles vous pouvez ensuite itérer au lieu d' avoir à écrire toutes
ces choses vous-même. Et comment faites-vous
cela ? Eh bien, vous écrivez
simplement une fonction, comme vous écririez
une fonction normale, sauf que les moules utilisent une
instruction return pour renvoyer une valeur, mais vous utilisez yield, return
et yields
renvoient une sorte de valeur, sauf que return
met fin à la fonction. Rendements. Il enregistre l'état de la fonction tel qu'il
est actuellement et renvoie la valeur. Ensuite, la prochaine fois
que vous appellerez la fonction, elle récupérera simplement cet état et
reprendra là
où elle s'était arrêtée.
20. Générateurs 2/4: J'ai ici un exemple très
simple de fonction de générateur. Vous voyez donc également que le type de retour est un générateur et
que
je parlerai de ce que ces choses font dans une minute. Mais c'est très simple. Nous avons une chaîne et nous donnons
la valeur de cette chaîne. C'est donc la première
fois que nous l'appelons. Mais ensuite, nous ajoutons un point d'
exclamation et nous le cédons à nouveau. Cela crée un
itérateur que vous pouvez appeler deux fois avant que la course ne
doive arrêter l'itération. Et puis, dans la fonction principale, j'utilise for-loop pour parcourir l'itérateur que ce simple
générateur nous fournit. Ensuite, j'
imprime la chaîne. Vous voyez donc ici quel est le
résultat de cette opération. Vous l'utilisez donc comme
un itérateur normal sauf que ce code n'est
exécuté que lorsque vous appelez la méthode
suivante pour la deuxième fois. Alors, quel est exactement
ce type ? Eh bien, cela dégénère
le type, vous pouvez importer depuis la saisie, et cela nous indique quelle est
la valeur de rendement. Vous pouvez donc voir que c'est
en fait une chaîne. Et ce que cela signifie alors que vous disposez réellement d'un mécanisme d' envoi d'informations pour
générer une fonction, puis que
ces informations sont
réutilisées pour le cycle suivant. Voici un exemple tiré de
la documentation Python qui montre comment cela fonctionne. C'est un peu avancé, mais s'il s'agit d'un cours
Python de niveau supérieur, alors pourquoi pas ? Mais en gros, ce qui
se passe ici, c'est que nous
stockons le résultat de l'expression yield, qui est ce que nous avons envoyé
à cette fonction. Et c'est du type float. Ensuite, pendant que nous obtenons
une valeur en utilisant le centre, nous allons en renvoyer la version
arrondie, qui est un entier, puis la dernière, qui est la valeur de retour. Vous pouvez donc réellement combiner le
rendement et le rendement dans un générateur et c'est à ce
moment-là
que la fonction s'arrête
et qu'elle reviendra. D'accord ? Donc, quand je l'exécute, vous
pouvez voir que j'ai ici une fonction principale où
je l'appelle ensuite. Ensuite, je lui envoie
ces valeurs. Ensuite, vous pouvez voir que cela passe par ces
choses et que cela se termine par :
OK, c'est essentiellement
comme ça que cela fonctionne. Donc, un autre cas
d'utilisation réel pour cela. Eh bien, pas beaucoup, pour être honnête,
vous en aurez peut-être un, mais je n'
ai jamais eu besoin de l'utiliser. Soyez également prudent lorsque vous
combinez les rendements et les rendements. De cette façon, je pense que cela
complique les choses, qu'il est plus difficile de comprendre
ce qui se passe réellement.
21. Générateurs 3/4: La prochaine chose que je
veux vous montrer on
appelle des
expressions génératrices. Et c'est aussi très puissant. Cela vous permet de créer une
expression qui est en fait un générateur et de spécifier le calcul immédiatement
dans l'expression. C'est un peu comme les fonctions
lambda, les fonctions anonymes, mais ensuite
ce sont des générateurs anonymes. Vous pouvez voir un exemple ici. J'ai un générateur de courant continu. Quand je passe la souris sur cette valeur, c'est qu'il s'agit en fait
d'un générateur, mais amusant et une
expression entre parenthèses, c'est l'expression du générateur. Et l'expression est deux à la puissance de I pour
I, dans une fourchette de dix. C'est donc un générateur limité. Ensuite, j'utilise une boucle for pour itérer sur ce
générateur de puissances, puis imprimer les générateurs de valeurs,
tout comme les entiers, les flottants
ou les fonctions sont des objets que vous pouvez transmettre à d'autres
fonctions, par exemple la fonction somme accepte un générateur et donc aussi
une expression de générateur. Vous pouvez donc très
facilement créer la somme de toutes ces choses en passant
simplement à
la fonction somme. Donc, quand je lance ça, c'est
ce que nous obtenons. La somme est de 1023. Les expressions génératrices sont
également très puissantes car elles permettent d'effectuer de tels
calculs, mais uniquement lorsque vous avez
réellement besoin de valoriser. C'est donc différent de,
disons, une compréhension par liste. Si je modifiais ces
paramètres par des crochets, nous aurions une compréhension de la
liste. Vous pouvez également répéter cela, mais la
compréhension de la liste est
déjà calculée lorsque vous la définissez en
tant que générateur. Cela se fait donc paresseusement, ce qui est très utile si vous souhaitez économiser du temps de
calcul.
22. Générateurs 4/4: Un autre avantage des générateurs est qu' ils s'intègrent
bien au code simultané. C'est l'une des leçons
précédentes dont
j'ai parlé sur le code asynchrone, les dont
j'ai parlé sur le code asynchrone, E/S et le code simultané. Eh bien, en fait, vous pouvez également avoir des générateurs de
concurrence asynchrones. Voici un exemple. J'
ai une fonction ici. C'est une
fonction asynchrone qui obtient un nom de Pokémon aléatoire. Il est donc basé sur l'
exemple Async IO que j'ai utilisé précédemment. Et cela renvoie simplement
le nom du Pokémon. Et puis j'ai ici une fonction
génératrice qui s'
appelle next
Pokemon après total. Ensuite, je fais une boucle
où je
passe en revue le total et chaque fois que j'utilise un poids pour obtenir le nom aléatoire du Pokémon
, puis je donne ce nom. Vous pouvez également utiliser Yield Away. Vous n'avez donc pas besoin
de varier ici. Mais comme vous pouvez le constater, il s'intègre très bien
au code asynchrone. Vous écrivez simplement asynchrone
devant et vous pouvez utiliser un poids dans votre générateur, puis ce sera
simultané. Le type est cependant différent. Il existe un async qui génère
un type comme vous le voyez ici. Mais en principe, l'idée est que cela
fonctionne de la même manière. Et puis, si vous regardez
la fonction principale, qui est également synchrone, nous avons une boucle asynchrone
qui passe par le générateur de Pokémon suivant et obtient les noms des Pokémon
suivants. Et vous pouvez utiliser des générateurs
asynchrones différentes
manières
et Python. Par exemple, j'ai
ici une liste de
compréhension qui utilise le prochain générateur
Pokemon asynchrone. Ensuite, j'utilise une compréhension de liste
asynchrone pour obtenir toutes ces données. Donc, quand je l'exécuterai, vous
verrez qu'il passe désormais par ces appels d'API et obtient
tous ces noms de Pokémon. Cela ne rassemble pas
toutes les réponses car c'est un
générateur, donc c'est paresseux. Il n'exécutera la
commande que lorsque vous la demanderez. C'est pourquoi nous les voyons
apparaître un par un. Mais cela signifie
que si vous n'avez
besoin que de cinq noms supplémentaires, vous
ne l'appelez que cinq
fois, ce qui
ne représente que cinq demandes d'API. Au lieu de faire toutes
les demandes d'API et de
ne prendre que cinq valeurs. C'est l'une des différences entre les indices de type du générateur et
la génération asynchrone d'un type. Et j'ai dû
corriger cela
il y a une minute parce que c'était
faux car l'asynchrone généré n'a pas
le type de valeur de retour, car ce n'est pas possible
avec l'asynchrone, nous n'avons que des rendements. C'est pourquoi il n'a que deux
arguments au lieu de trois. Mais encore une fois, ce
n'est pas quelque chose que vous utiliseriez normalement
beaucoup dans votre code. Alors pourquoi est-ce utile ? Eh bien, il existe un moyen simple de
créer des itérateurs sans avoir à créer de classe avec méthodes
iter et next dunder. Bien entendu, ils
s'intègrent également bien aux enfants
ou aux outils dont il a été
question dans la leçon précédente, économisent
la mémoire et
évitent des calculs inutiles. Si vous ne demandez pas la valeur, elle n'est pas calculée. Et en général, c'est un excellent
moyen de représenter, par exemple, des
flux de données sur un réseau. Chaque fois que des
flux de données sur un réseau vous recevez
un élément
suivant depuis le réseau, vous devez faire attention
au fait que générateurs peuvent couche plus difficile
à comprendre, en particulier si vous commencez à
combiner les instructions yield et return dans
un seul générateur. Ensuite, étant donné que le
code n'est exécuté que sur demande, il est possible que vous ne
rencontriez une erreur
qu'après un
certain temps, ce qui pourrait entraîner une
boîte inattendue et plus tard Vous devez
donc vous
assurer que vous les testez correctement. Donc, dans l'ensemble,
les générateurs sont de très bons outils, ne les utilisent
peut-être pas tout le temps, mais dans certains cas, ils
sont vraiment utiles. Passons maintenant à la dernière leçon sur les gestionnaires de
contextes.
23. Gestionnaires de contexte 1/4: La dernière fonctionnalité Python
que je souhaite aborder dans ce cours
est ce que l'on appelle le gestionnaire de
contexte. Et cela s'appuie sur d'autres fonctionnalités dont
j'ai parlé dans les leçons précédentes, telles que
les itérateurs et les générateurs. Et il est également compatible
avec le code asynchrone, comme je vais vous le montrer dans
une minute, les contextes les gestionnaires sont vraiment
utiles car ils vous permettent de
contrôler ce qui se passe lorsque vous créez, détruisez,
détruisez une ressource. Et vous pouvez vous assurer que, par exemple s'il y a une exception ou s'il existe une
autre raison ou s'il existe une
autre raison pour laquelle
le programme doit arrêter de
faire ce qu'il fait, vous pouvez utiliser un
gestionnaire de contexte pour contrôler ce qui se passe
afin de libérer une ressource. Cela est utile, par exemple, si vous devez fermer un fichier, si vous devez fermer
la connexion à la base car vous devez faire remarquer à une
autre surface que votre application arrête une tâche et vous voulez vous
assurer que cela se produit toujours. C'est là que
les gestionnaires de contextes sont vraiment utiles. C'est dans l'une des
leçons précédentes que je vous ai montré comment
ouvrir un fichier à l'aide de
l'instruction width. Il s'agit en fait d'un exemple
de gestionnaire de contexte. Et la raison pour laquelle nous utilisons une
instruction de largeur est qu' elle permet au fichier Context
Manager, Context Manager, de se fermer correctement une fois que vous avez fini de
lire le contenu. Et il existe deux méthodes de
Dahmer, encore une fois, qui sont importantes. Il y a les méthodes d'entrée et de
sortie dominantes. Enter est l'endroit où vous placez tout ce qui doit
se passer lorsque vous créez une ressource et sortez chaque fois que vous devez
détruire la ressource.
24. Gestionnaires de contexte 2/4: Voici un autre exemple
d'utilisation d'un gestionnaire de contexte. J'utilise SQL Lite Three
ici, cela se connecte à une base de données qui
n'est qu'un fichier local. Ensuite, je sélectionne des éléments
à partir d'une table de blocs. Et vous voyez qu'ici,
nous créons simplement une connexion avec des connexions à points
sqlite, mais vous pouvez en
fait l'utiliser comme gestionnaire de contexte. Lorsque je lance ce code
, voici ce que nous voyons. Vous voyez donc que nous obtenons essentiellement une liste
de blogs. Mais le fait est que nous devons nous assurer de toujours
fermer la connexion, n' est-ce pas ? C'est donc ce qui se passe ici. C'est pourquoi il ne s'agit pas
d'un blocage final. Donc, si je fais par exemple une faute de frappe ici, alors des blogs qui n'existent pas. Nous allons donc avoir
une sorte d'erreur qui ne figure pas dans le tableau. Cela permet de s'assurer que la connexion est
correctement fermée. Maintenant, si vous voulez éviter d'avoir à écrire ceci, essayez enfin, qui peut également être
fait en utilisant sqlite point connect comme gestionnaire de contexte. écrivons donc simplement la largeur sqlite point connect en tant que collection. Et puis,
bien sûr, je dois le mettre en retrait et il
devrait y avoir une colonne ici. Ce que je peux faire maintenant, c'est
faire la même chose, imprimer les blogs, mais ensuite
je peux introduire une erreur. Mais la seule chose
est que vous
pouvez maintenant voir que dans le journal,
cela ne
ferme pas correctement la connexion. Ceci est principalement utilisé pour annuler les transactions dans la base
de données, etc. Ce qui est bien avec Python,
c'est que nous pouvons créer nos propres gestionnaires de
contextes. Nous devons simplement fournir
une classe dotée d'une méthode dunder
d'entrée et de sortie ,
puis l'utiliser à la place. Vous en voyez donc un exemple. J'ai créé une classe sqlite. Je lui fournis le nom
de fichier, donc c'est l'application de TB. Et je stocke une
nouvelle connexion pour connecter à la base de données
dans la méthode enter, puis
j'obtiens le curseur
puis la sortie. Je ne valide pas les modifications, puis je ferme la connexion. Donc, dans notre fonction principale,
nous avons avec SQL light. J'utilise donc maintenant ce gestionnaire de
contexte ici, qui va me donner
le curseur, puis je pourrai exécuter ma requête et
renvoyer le résultat. Donc, quand je l'exécuterai,
nous
obtiendrons à nouveau exactement les
mêmes résultats, n'est-ce pas ? Nous allons imprimer ces blogs,
mais ensuite ils appelleront « répondre » et sortir » une fois que tout sera terminé. Nous sommes donc sûrs que la connexion est toujours fermée, car maintenant, par exemple permettez-moi de présenter
à nouveau une erreur. Si je le lance à nouveau, vous verrez qu'il
a toujours appelé Entrée et Sortie. Le gestionnaire de contexte a réussi à
fermer correctement la connexion, même en cas d'erreur.
25. Gestionnaires de contexte 3/4: Maintenant, au lieu de cette classe
avec des méthodes d'entrée et de sortie, vous pouvez également utiliser un
décorateur qui
s'appuie sur la génération d'une fonction évoquée
dans la leçon précédente. Voilà à quoi ça ressemble. J'importe le décorateur du
gestionnaire de contexte à partir de contextes en direct et c'est
amusant de le
faire ici pour indiquer que cette fonction va
être un gestionnaire de contexte. Et puis, vous voyez, j'utilise
une structure de générateur avec rendement pour
définir réellement ce qui doit se passer dans les parties réponse
et sortie. Donc, la façon dont cela fonctionne, c'est
que tout ce qui précède les rendements est
la pièce maîtresse. Tout ce qui suit
est la partie de sortie. Donc, c'est essentiellement
ce que vous voyez ici. Et cela a exactement le même
effet que l'utilisation d'une classe. Ou si je lance ceci, vous
voyez que nous obtenons une connexion qui se ferme ici, qu'une connexion se
crée et
que nous imprimons les blogs. Si je supprime à nouveau ici, retirons un autre
personnage juste pour le fun. Et puis réexécutons-le. Vous voyez, nous avons toujours cette erreur, mais maintenant elle ferme correctement la
connexion car nous utilisons un
gestionnaire de contexte, un décorateur.
26. Gestionnaires de contexte 4/4: La dernière chose que je
veux vous montrer est que les gestionnaires de
contexte
prennent également en charge la syntaxe asynchrone et attend de l' intégration du code
simultané, tout comme les générateurs,
si elle souhaite accorder un gestionnaire de
contexte asynchrone, utilisaient le décorateur asynchrone du
gestionnaire de contexte. Maintenant, il y a quelques
problèmes de frappe ici, car
il s'agit d'un exemple plus approximatif. Mais l'idée est que vous
utilisez dans ce cas générateur
asynchrone au lieu d'
un générateur synchrone normal. Les gestionnaires de contextes travaillent donc également
dans ce sens. Donc, par exemple, supposons que vous ayez une couche de base de données asynchrone. Vous pouvez utiliser la
syntaxe asynchrone await pour y accéder, par exemple , la connexion à la
base de données, nous
utilisons la connexion et publication est également asynchrone et nous avons placé l'async devant. Ensuite, vous pouvez l'utiliser
dans le reste de votre code, comme je le fais ici, par exemple, je reçois tous les utilisateurs. Sql light lui-même
n'est pas asynchrone, mais il existe un package
appelé sclerites qui est asynchrone que vous pouvez utiliser pour
accéder à une
base de données SQL Light de manière asynchrone. Vous voyez un exemple simple
de la façon dont cela fonctionne. Donc, au lieu de
sqlite point connect, je le fais, je connecte tous sqlite point connect. Mais c'est asynchrone, tout en utilisant les instructions de
largeur. Et vous faites la même
chose pour un curseur récupère toutes les
données de la table. Donc, lorsque vous l'utilisez, eh bien, les endroits les plus importants où vous devez vous
assurer bien fermer ou de
nettoyer votre désordre, même en cas de
problème. Et c'est particulièrement
le cas des bases de données dont nous assurons le
suivi des connexions. Ou vous voulez
vous assurer de fermer cette connexion. Ou peut-être devez-vous laisser un nœud d'API indiquer que vous avez
terminé une sorte de processus, vous voulez vous assurer
que même si une exception se produit, cet
appel final se produit toujours. Et c'est là que
les gestionnaires de contexte sont vraiment utiles. Enfin, du point de vue de la
conception logicielle, il est vraiment intéressant de
pouvoir regrouper la création et destruction de ressources
en un seul endroit.
27. Conclusion: Merci beaucoup d'avoir
suivi ce cours. J'espère que cela vous a donné matière
à réflexion et vous a donné quelques idées sur la façon d'améliorer
votre code Python existant. J'ai eu beaucoup de plaisir à
enregistrer ce cours, mais il y a bien sûr une tonne d' autres choses dans lesquelles nous pourrions nous plonger. Pour en savoir plus sur Python, en particulier sur la conception de
logiciels, comme je l'ai mentionné
au début, consultez ma chaîne YouTube, youtube.com slash ion codes. Si vous avez des questions ou des suggestions,
écrivez simplement un commentaire ici. J'adorerais avoir
de tes nouvelles. Merci d'avoir regardé et prenez soin de vous.