[{"data":1,"prerenderedAt":910},["ShallowReactive",2],{"page-\u002Fpython\u002Fclasses-et-environnements":3,"pieces-python":868,"autour-\u002Fpython\u002Fclasses-et-environnements":893,"prerequis-\u002Fpython\u002Fclasses-et-environnements":897,"plan-python":899},{"id":4,"title":5,"body":6,"description":836,"extension":837,"ligne":49,"meta":838,"motsCles":839,"navigation":117,"niveau":841,"path":842,"prerequis":843,"ressources":845,"seo":857,"sources":858,"stem":866,"__hash__":867},"docs\u002Fpython\u002F06.classes-et-environnements.md","Classes, annotations et environnements virtuels",{"type":7,"value":8,"toc":824},"minimark",[9,14,27,31,44,210,221,230,239,252,255,294,302,306,309,383,398,415,419,432,532,545,558,562,569,576,580,590,610,615,665,677,681,687,709,712,741,744,764,768,820],[10,11,13],"h2",{"id":12},"ce-que-tu-vas-apprendre","Ce que tu vas apprendre",[15,16,17,21,24],"ul",{},[18,19,20],"li",{},"Regrouper des données et des fonctions dans une classe.",[18,22,23],{},"Indiquer les types attendus avec des annotations.",[18,25,26],{},"Isoler un projet dans un environnement virtuel et y installer des paquets.",[10,28,30],{"id":29},"une-première-classe","Une première classe",[32,33,34,35,39,40,43],"p",{},"Une ",[36,37,38],"strong",{},"classe"," est un plan pour fabriquer des ",[36,41,42],{},"objets"," qui partagent la même structure et les mêmes comportements.",[45,46,51],"pre",{"className":47,"code":48,"language":49,"meta":50,"style":50},"language-python shiki shiki-themes github-light-default github-dark-default github-dark-default","class Recette:\n    def __init__(self, nom, portions):\n        self.nom = nom\n        self.portions = portions\n\n    def afficher(self):\n        print(f\"{self.nom} ({self.portions} portions)\")\n\ncrepes = Recette(\"Crêpes\", 4)\ncrepes.afficher()\n","python","",[52,53,54,71,84,99,112,119,131,177,182,204],"code",{"__ignoreMap":50},[55,56,59,63,67],"span",{"class":57,"line":58},"line",1,[55,60,62],{"class":61},"sOnC1","class",[55,64,66],{"class":65},"sIXEE"," Recette",[55,68,70],{"class":69},"scfrF",":\n",[55,72,74,77,81],{"class":57,"line":73},2,[55,75,76],{"class":61},"    def",[55,78,80],{"class":79},"s5iOY"," __init__",[55,82,83],{"class":69},"(self, nom, portions):\n",[55,85,87,90,93,96],{"class":57,"line":86},3,[55,88,89],{"class":79},"        self",[55,91,92],{"class":69},".nom ",[55,94,95],{"class":61},"=",[55,97,98],{"class":69}," nom\n",[55,100,102,104,107,109],{"class":57,"line":101},4,[55,103,89],{"class":79},[55,105,106],{"class":69},".portions ",[55,108,95],{"class":61},[55,110,111],{"class":69}," portions\n",[55,113,115],{"class":57,"line":114},5,[55,116,118],{"emptyLinePlaceholder":117},true,"\n",[55,120,122,124,128],{"class":57,"line":121},6,[55,123,76],{"class":61},[55,125,127],{"class":126},"syCW7"," afficher",[55,129,130],{"class":69},"(self):\n",[55,132,134,137,140,143,147,150,153,156,159,162,164,166,169,171,174],{"class":57,"line":133},7,[55,135,136],{"class":79},"        print",[55,138,139],{"class":69},"(",[55,141,142],{"class":61},"f",[55,144,146],{"class":145},"shWOn","\"",[55,148,149],{"class":61},"{",[55,151,152],{"class":79},"self",[55,154,155],{"class":69},".nom",[55,157,158],{"class":61},"}",[55,160,161],{"class":145}," (",[55,163,149],{"class":61},[55,165,152],{"class":79},[55,167,168],{"class":69},".portions",[55,170,158],{"class":61},[55,172,173],{"class":145}," portions)\"",[55,175,176],{"class":69},")\n",[55,178,180],{"class":57,"line":179},8,[55,181,118],{"emptyLinePlaceholder":117},[55,183,185,188,190,193,196,199,202],{"class":57,"line":184},9,[55,186,187],{"class":69},"crepes ",[55,189,95],{"class":61},[55,191,192],{"class":69}," Recette(",[55,194,195],{"class":145},"\"Crêpes\"",[55,197,198],{"class":69},", ",[55,200,201],{"class":79},"4",[55,203,176],{"class":69},[55,205,207],{"class":57,"line":206},10,[55,208,209],{"class":69},"crepes.afficher()\n",[32,211,212,213,216,217,220],{},"Le programme affiche « Crêpes (4 portions) ». ",[52,214,215],{},"Recette(\"Crêpes\", 4)"," crée un objet, une ",[36,218,219],{},"instance"," de la classe.",[10,222,224,227,228],{"id":223},"__init__-et-self",[52,225,226],{},"__init__"," et ",[52,229,152],{},[32,231,232,234,235,238],{},[52,233,226],{}," est la méthode appelée à la création de l'objet. Elle range les valeurs de départ dans ses ",[36,236,237],{},"attributs",".",[32,240,241,243,244,247,248,251],{},[52,242,152],{}," désigne l'objet lui-même. C'est toujours le premier paramètre d'une ",[36,245,246],{},"méthode",", c'est-à-dire d'une fonction définie dans une classe. Python le remplit tout seul : tu écris ",[52,249,250],{},"crepes.afficher()"," sans argument.",[32,253,254],{},"Chaque instance a ses propres valeurs :",[45,256,258],{"className":47,"code":257,"language":49,"meta":50,"style":50},"gratin = Recette(\"Gratin\", 6)\nprint(gratin.portions)\nprint(crepes.portions)\n",[52,259,260,279,287],{"__ignoreMap":50},[55,261,262,265,267,269,272,274,277],{"class":57,"line":58},[55,263,264],{"class":69},"gratin ",[55,266,95],{"class":61},[55,268,192],{"class":69},[55,270,271],{"class":145},"\"Gratin\"",[55,273,198],{"class":69},[55,275,276],{"class":79},"6",[55,278,176],{"class":69},[55,280,281,284],{"class":57,"line":73},[55,282,283],{"class":79},"print",[55,285,286],{"class":69},"(gratin.portions)\n",[55,288,289,291],{"class":57,"line":86},[55,290,283],{"class":79},[55,292,293],{"class":69},"(crepes.portions)\n",[32,295,296,297,299,300,238],{},"Résultat : ",[52,298,276],{}," puis ",[52,301,201],{},[10,303,305],{"id":304},"ajouter-un-comportement","Ajouter un comportement",[32,307,308],{},"Une méthode peut modifier l'objet ou calculer à partir de ses attributs.",[45,310,312],{"className":47,"code":311,"language":49,"meta":50,"style":50},"class Recette:\n    def __init__(self, nom, portions):\n        self.nom = nom\n        self.portions = portions\n        self.ingredients = []\n\n    def ajouter(self, ingredient):\n        self.ingredients.append(ingredient)\n",[52,313,314,322,330,340,350,362,366,376],{"__ignoreMap":50},[55,315,316,318,320],{"class":57,"line":58},[55,317,62],{"class":61},[55,319,66],{"class":65},[55,321,70],{"class":69},[55,323,324,326,328],{"class":57,"line":73},[55,325,76],{"class":61},[55,327,80],{"class":79},[55,329,83],{"class":69},[55,331,332,334,336,338],{"class":57,"line":86},[55,333,89],{"class":79},[55,335,92],{"class":69},[55,337,95],{"class":61},[55,339,98],{"class":69},[55,341,342,344,346,348],{"class":57,"line":101},[55,343,89],{"class":79},[55,345,106],{"class":69},[55,347,95],{"class":61},[55,349,111],{"class":69},[55,351,352,354,357,359],{"class":57,"line":114},[55,353,89],{"class":79},[55,355,356],{"class":69},".ingredients ",[55,358,95],{"class":61},[55,360,361],{"class":69}," []\n",[55,363,364],{"class":57,"line":121},[55,365,118],{"emptyLinePlaceholder":117},[55,367,368,370,373],{"class":57,"line":133},[55,369,76],{"class":61},[55,371,372],{"class":126}," ajouter",[55,374,375],{"class":69},"(self, ingredient):\n",[55,377,378,380],{"class":57,"line":179},[55,379,89],{"class":79},[55,381,382],{"class":69},".ingredients.append(ingredient)\n",[32,384,385,386,389,390,393,394,397],{},"Chaque recette démarre avec sa propre liste vide. Après ",[52,387,388],{},"crepes.ajouter(\"farine\")",", la liste ",[52,391,392],{},"crepes.ingredients"," contient « farine » et celle de ",[52,395,396],{},"gratin"," reste vide.",[399,400,401],"tip",{},[32,402,403,404,407,408,411,412,414],{},"Pour une classe qui ne fait que stocker des données, regarde le décorateur ",[52,405,406],{},"dataclass"," du module ",[52,409,410],{},"dataclasses",". Il écrit ",[52,413,226],{}," à ta place.",[10,416,418],{"id":417},"les-annotations-de-types","Les annotations de types",[32,420,34,421,424,425,428,429,238],{},[36,422,423],{},"annotation de type"," indique le type attendu d'une variable, d'un paramètre ou d'un retour. Elle s'écrit avec un ",[52,426,427],{},":"," et une flèche ",[52,430,431],{},"->",[45,433,435],{"className":47,"code":434,"language":49,"meta":50,"style":50},"def prix_total(prix: float, portions: int) -> float:\n    return prix * portions\n\nclass Recette:\n    def __init__(self, nom: str, portions: int) -> None:\n        self.nom = nom\n        self.portions = portions\n",[52,436,437,464,477,481,489,512,522],{"__ignoreMap":50},[55,438,439,442,445,448,451,454,457,460,462],{"class":57,"line":58},[55,440,441],{"class":61},"def",[55,443,444],{"class":126}," prix_total",[55,446,447],{"class":69},"(prix: ",[55,449,450],{"class":79},"float",[55,452,453],{"class":69},", portions: ",[55,455,456],{"class":79},"int",[55,458,459],{"class":69},") -> ",[55,461,450],{"class":79},[55,463,70],{"class":69},[55,465,466,469,472,475],{"class":57,"line":73},[55,467,468],{"class":61},"    return",[55,470,471],{"class":69}," prix ",[55,473,474],{"class":61},"*",[55,476,111],{"class":69},[55,478,479],{"class":57,"line":86},[55,480,118],{"emptyLinePlaceholder":117},[55,482,483,485,487],{"class":57,"line":101},[55,484,62],{"class":61},[55,486,66],{"class":65},[55,488,70],{"class":69},[55,490,491,493,495,498,501,503,505,507,510],{"class":57,"line":114},[55,492,76],{"class":61},[55,494,80],{"class":79},[55,496,497],{"class":69},"(self, nom: ",[55,499,500],{"class":79},"str",[55,502,453],{"class":69},[55,504,456],{"class":79},[55,506,459],{"class":69},[55,508,509],{"class":79},"None",[55,511,70],{"class":69},[55,513,514,516,518,520],{"class":57,"line":121},[55,515,89],{"class":79},[55,517,92],{"class":69},[55,519,95],{"class":61},[55,521,98],{"class":69},[55,523,524,526,528,530],{"class":57,"line":133},[55,525,89],{"class":79},[55,527,106],{"class":69},[55,529,95],{"class":61},[55,531,111],{"class":69},[32,533,534,535,198,538,541,542,238],{},"Pour les listes et les dictionnaires, précise le contenu entre crochets : ",[52,536,537],{},"list[str]",[52,539,540],{},"dict[str, int]",". Une valeur facultative s'écrit ",[52,543,544],{},"str | None",[546,547,548],"warning",{},[32,549,550,551,554,555,238],{},"Python n'applique pas les annotations à l'exécution : appeler ",[52,552,553],{},"prix_total(\"a\", \"b\")"," ne produit pas d'erreur de type à lui seul. Elles servent à la lecture et aux outils comme l'éditeur ou ",[52,556,557],{},"mypy",[10,559,561],{"id":560},"pourquoi-un-environnement-virtuel","Pourquoi un environnement virtuel",[32,563,564,565,568],{},"Chaque projet a besoin de ses propres bibliothèques, parfois dans des versions différentes. Un ",[36,566,567],{},"environnement virtuel"," est un dossier qui contient une copie isolée de Python et ses paquets, propre à un projet.",[32,570,571,572,575],{},"Le module ",[52,573,574],{},"venv"," est livré avec Python. Il évite de mélanger les dépendances de tous tes projets.",[10,577,579],{"id":578},"créer-et-activer-un-environnement","Créer et activer un environnement",[581,582,583],"ol",{},[18,584,585,586,589],{},"Crée l'environnement dans un dossier ",[52,587,588],{},".venv"," :",[45,591,595],{"className":592,"code":593,"language":594,"meta":50,"style":50},"language-bash shiki shiki-themes github-light-default github-dark-default github-dark-default","python -m venv .venv\n","bash",[52,596,597],{"__ignoreMap":50},[55,598,599,601,604,607],{"class":57,"line":58},[55,600,49],{"class":65},[55,602,603],{"class":79}," -m",[55,605,606],{"class":145}," venv",[55,608,609],{"class":145}," .venv\n",[581,611,612],{"start":73},[18,613,614],{},"Active-le. La commande dépend de ton système :",[616,617,618,631],"table",{},[619,620,621],"thead",{},[622,623,624,628],"tr",{},[625,626,627],"th",{},"Système",[625,629,630],{},"Commande d'activation",[632,633,634,645,655],"tbody",{},[622,635,636,640],{},[637,638,639],"td",{},"Windows (PowerShell)",[637,641,642],{},[52,643,644],{},".venv\\Scripts\\Activate.ps1",[622,646,647,650],{},[637,648,649],{},"Windows (cmd)",[637,651,652],{},[52,653,654],{},".venv\\Scripts\\activate.bat",[622,656,657,660],{},[637,658,659],{},"macOS et Linux",[637,661,662],{},[52,663,664],{},"source .venv\u002Fbin\u002Factivate",[581,666,667],{"start":86},[18,668,669,670,673,674,238],{},"Le terminal affiche ",[52,671,672],{},"(.venv)"," au début de la ligne. Tu peux en sortir avec ",[52,675,676],{},"deactivate",[10,678,680],{"id":679},"installer-des-paquets-avec-pip","Installer des paquets avec pip",[32,682,683,686],{},[36,684,685],{},"pip"," est l'outil qui installe des paquets publiés par la communauté. Environnement activé :",[45,688,690],{"className":592,"code":689,"language":594,"meta":50,"style":50},"pip install requests\npip list\n",[52,691,692,702],{"__ignoreMap":50},[55,693,694,696,699],{"class":57,"line":58},[55,695,685],{"class":65},[55,697,698],{"class":145}," install",[55,700,701],{"class":145}," requests\n",[55,703,704,706],{"class":57,"line":73},[55,705,685],{"class":65},[55,707,708],{"class":145}," list\n",[32,710,711],{},"Pour que quelqu'un d'autre retrouve les mêmes paquets, note-les dans un fichier :",[45,713,715],{"className":592,"code":714,"language":594,"meta":50,"style":50},"pip freeze > requirements.txt\npip install -r requirements.txt\n",[52,716,717,730],{"__ignoreMap":50},[55,718,719,721,724,727],{"class":57,"line":58},[55,720,685],{"class":65},[55,722,723],{"class":145}," freeze",[55,725,726],{"class":61}," >",[55,728,729],{"class":145}," requirements.txt\n",[55,731,732,734,736,739],{"class":57,"line":73},[55,733,685],{"class":65},[55,735,698],{"class":145},[55,737,738],{"class":79}," -r",[55,740,729],{"class":145},[32,742,743],{},"La première commande écrit la liste des paquets installés. La seconde les réinstalle sur une autre machine.",[745,746,747],"caution",{},[32,748,749,750,752,753,756,757,760,761,238],{},"N'ajoute jamais le dossier ",[52,751,588],{}," à Git. Il est volumineux et propre à ta machine. Mets ",[52,754,755],{},".venv\u002F"," dans ton ",[52,758,759],{},".gitignore"," et partage seulement ",[52,762,763],{},"requirements.txt",[10,765,767],{"id":766},"à-retenir","À retenir",[15,769,770,777,785,795,801,811],{},[18,771,772,773,776],{},"Une classe est un plan ; ",[52,774,775],{},"Recette(...)"," crée une instance qui a ses propres attributs.",[18,778,779,781,782,784],{},[52,780,226],{}," initialise l'objet, ",[52,783,152],{}," le désigne dans chaque méthode.",[18,786,787,788,198,791,794],{},"Les annotations (",[52,789,790],{},"nom: str",[52,792,793],{},"-> float",") documentent les types sans les imposer à l'exécution.",[18,796,797,800],{},[52,798,799],{},"python -m venv .venv"," crée un environnement, qu'on active selon son système.",[18,802,803,806,807,810],{},[52,804,805],{},"pip install"," ajoute un paquet, ",[52,808,809],{},"pip freeze > requirements.txt"," fige la liste.",[18,812,813,814,816,817,819],{},"Le dossier ",[52,815,588],{}," ne se commite pas ; ",[52,818,763],{},", si.",[821,822,823],"style",{},"html pre.shiki code .sOnC1, html code.shiki .sOnC1{--shiki-light:#CF222E;--shiki-default:#FF7B72;--shiki-dark:#FF7B72}html pre.shiki code .sIXEE, html code.shiki .sIXEE{--shiki-light:#953800;--shiki-default:#FFA657;--shiki-dark:#FFA657}html pre.shiki code .scfrF, html code.shiki .scfrF{--shiki-light:#1F2328;--shiki-default:#E6EDF3;--shiki-dark:#E6EDF3}html pre.shiki code .s5iOY, html code.shiki .s5iOY{--shiki-light:#0550AE;--shiki-default:#79C0FF;--shiki-dark:#79C0FF}html pre.shiki code .syCW7, html code.shiki .syCW7{--shiki-light:#8250DF;--shiki-default:#D2A8FF;--shiki-dark:#D2A8FF}html pre.shiki code .shWOn, html code.shiki .shWOn{--shiki-light:#0A3069;--shiki-default:#A5D6FF;--shiki-dark:#A5D6FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":50,"searchDepth":73,"depth":86,"links":825},[826,827,828,830,831,832,833,834,835],{"id":12,"depth":73,"text":13},{"id":29,"depth":73,"text":30},{"id":223,"depth":73,"text":829},"__init__ et self",{"id":304,"depth":73,"text":305},{"id":417,"depth":73,"text":418},{"id":560,"depth":73,"text":561},{"id":578,"depth":73,"text":579},{"id":679,"depth":73,"text":680},{"id":766,"depth":73,"text":767},"Modéliser des objets avec les classes, documenter les types avec les annotations, et isoler chaque projet avec venv et pip.","md",{},[38,840,226,152,246,423,574,685,763,567],"objet","avance","\u002Fpython\u002Fclasses-et-environnements",[844],"\u002Fpython\u002Ffichiers-et-exceptions",[846,850,853],{"nom":847,"url":848,"type":849},"Le tutoriel officiel Python, les classes","https:\u002F\u002Fdocs.python.org\u002Ffr\u002F3\u002Ftutorial\u002Fclasses.html","doc",{"nom":851,"url":852,"type":849},"Le tutoriel officiel Python, environnements virtuels et paquets","https:\u002F\u002Fdocs.python.org\u002Ffr\u002F3\u002Ftutorial\u002Fvenv.html",{"nom":854,"url":855,"type":856},"Grafikart, Apprendre Python","https:\u002F\u002Fgrafikart.fr\u002Ftutoriels\u002Fpython","cours",{"title":5,"description":836},[859,861,863],{"nom":860,"url":848},"Documentation de Python, les classes",{"nom":862,"url":852},"Documentation de Python, environnements virtuels et paquets",{"nom":864,"url":865},"Documentation de Python, le module typing","https:\u002F\u002Fdocs.python.org\u002Ffr\u002F3\u002Flibrary\u002Ftyping.html","python\u002F06.classes-et-environnements","I8L4meUAVk-gxJr_BppqyRJ9A06SvycsIRm0VcSCX7s",[869,873,877,881,885,888,889],{"path":870,"title":871,"stem":872},"\u002Fpython\u002Fpremiers-pas","Premiers pas avec Python","python\u002F01.premiers-pas",{"path":874,"title":875,"stem":876},"\u002Fpython\u002Fconditions-et-boucles","Conditions et boucles","python\u002F02.conditions-et-boucles",{"path":878,"title":879,"stem":880},"\u002Fpython\u002Ffonctions-et-modules","Fonctions et modules","python\u002F03.fonctions-et-modules",{"path":882,"title":883,"stem":884},"\u002Fpython\u002Fcollections","Listes, dictionnaires et tuples","python\u002F04.collections",{"path":844,"title":886,"stem":887},"Fichiers, exceptions et JSON","python\u002F05.fichiers-et-exceptions",{"path":842,"title":5,"stem":866},{"path":890,"title":891,"stem":892},"\u002Fpython","Python","python\u002Findex",[894,896],{"title":886,"path":844,"stem":887,"description":895,"children":-1},"Lire et écrire des fichiers avec with open, gérer les erreurs avec try et except, et sauvegarder des données au format JSON.",null,[898],{"path":844,"title":886,"ligne":49},[900,902,903,904,906,907,908],{"path":870,"title":871,"niveau":901,"stem":872},"debutant",{"path":874,"title":875,"niveau":901,"stem":876},{"path":878,"title":879,"niveau":901,"stem":880},{"path":882,"title":883,"niveau":905,"stem":884},"intermediaire",{"path":844,"title":886,"niveau":905,"stem":887},{"path":842,"title":5,"niveau":841,"stem":866},{"path":890,"title":891,"niveau":909,"stem":892},"memo",1794583460014]