 Bonjour à tous. Aujourd'hui, je vais vous parler de ce avec quoi j'ai joué récemment, l'exploration de ces pitons et les internals avec le module C-Type. Déjà rapidement, c'est quoi ? C'est l'implémentation standard de pitons qui est écrite en C. C-Type, c'est quoi ? C'est un module piton qui n'est pas souvent utilisé mais qui est super pratique. Pourquoi j'ai fait ça ? Parce que j'aime bien jouer avec ce langage. J'aime beaucoup les tripatouilles dans les trucs très profonds, les métaclastes, les trucs qui marchent bien mais que personne sait servir moi non plus. Et il y a des faux, quand je comprends pas trop comment ça marche, je lis le code C. Et un avantage de ces pitons, c'est que le code est super bien écrit. C'est-à-dire que si vous avez jamais lu de C, il faut s'y mettre un petit peu, mais si vous avez déjà lu, ça se lit tout seul. Donc voilà. Qu'est-ce qu'on va avoir aujourd'hui dans cette prétentation ? On va avoir du piton quand même, on est là pour ça. Un peu de C parce que c'est écrit en C et il va falloir tuer un peu de C. Et des craches parce que je fais des live-démos et qu'on touche à des trucs qu'on ne devrait pas toucher. Donc si je me rate, ça va cracher. C'est rigolo. Donc n'hésitez pas surtout de choses. J'ai tendance à parler un peu vite. Donc si je parle trop vite, dites-le moi. Et si vous avez des questions sur quoi que ce soit, sur le C, sur le piton, sur ce que vous voyez, n'hésitez pas à me poser des questions. J'ai l'interprèteur, j'ai le code à côté. Donc allez-y. Donc de quoi on va parler, vous le verrez bien. On va commencer par les outils dont on a besoin pour pouvoir travailler et étudier toutes ces choses-là. Donc le premier, c'est le module C type. Le module C type, c'est quoi ? C'est un module d'interfassage entre piton et le C. Donc ça permet entre autres d'exporter des types compatibles avec le C. C'est-à-dire qu'un int piton et un int C, c'est pas la même chose. On le verra très rapidement. Et si on essaie de passer un int piton à du code C, ça va juste pas marcher. Ça permet d'appeler des fonctions C. Ça c'est super pratique. C'est-à-dire que vous avez votre fonction C. Vous voulez l'appeler depuis du code piton, ça va fonctionner. Et enfin, ça permet aussi de travailler avec des structures C. On va le voir. Vous avez vos structures C. Vous voulez la même chose en piton, il y a moyen. Et donc ça permet de haquer un peu le piton, vu que vous bossez à partir du C directement. Vous pouvez faire des choses qu'on n'a pas le droit de faire. Donc le module C type commence à se présenter. Donc ça permet de faire plusieurs choses. Et là, c'est l'export des librairies, par exemple, faire des bibliothèques, pardon. Donc par exemple, on peut récupérer la lib C. Donc on est sous l'inux avec son nom c'est libc.so.6. On récupère la lib C et on peut récupérer des pointeurs de fonctions. Par exemple là, on a Cslip qui est un pointeur vers le slip de la lib C. Et on a Fry qui est un pointeur vers la fonction strFry de la lib C. Et on a Name qui est le nom de notre module. Alors si on prend le fichier donc CtypeDemo.py Je ne suis pas dans le bon. C'est celui d'au-dessus. C'est CtypeDemo.py. Donc comme on peut le voir là, on a la fonction Cslip qui est donc un pointeur de fonction vers une fonction qui est la fonction slip. Donc si on l'appelle, on fait un slip. Et là, ce n'est pas le slip de Python, c'est le slip de la lib C directement. C'est-à-dire qu'il y a une fonction de la lib C que vous connaissez et que vous ne pouvez pas utiliser depuis le Python, vous pouvez. Par exemple, la fonction strFry, qui est dans la lib C, personne ne sait pourquoi. C'est une fonction qui permet de remuer les lettres d'une string. Par exemple, vous lui donnez une string, ça permet de le remuer. Le problème étant, on a name, qui est le nom de notre module Ctype. On a fry qui est la fonction strFry. Surmu, pardon. Surmu, c'est comme ça. Le fait est que ça nous renvoie un pointeur, on s'en fiche. Mais le truc, c'est que ça fait une modification en place. Et en pittons, les modifications de string en place n'existent pas. C'est-à-dire que la name, maintenant, a changé. On se dit quel est le problème. Si on regarde notre module Ctype, c'est le module qui a plus un nom différent. Et ça déjà, ça montre que le module Ctype permet de bypasser la logique de pittons et de passer derrière en faisant des modifications en place de strings en accédant à des adresses mémoires qu'on ne devrait pas pouvoir accéder. Donc là, il faut vraiment voir le côté module Ctipsm from la lib C. La lib pitton, pardon. Et voilà. Donc ça, c'est Ctype en lui-même. Ça permet aussi un truc super utile dont on va se servir. C'est le from-adresse. Par exemple, on a la lib C, pareil qu'on récupère. Et on appelle malloc, malloc de 4. On va récupérer cet adresse-là. Et malloc, qui permet d'allouer de la mémoire, on va pouvoir après récupérer un int pitton, enfin c'est pitton, qui va permettre de travailler directement dessus. Et par exemple, ce qu'on voit là, c'est le malloc int. Si on le travaille dans le fichier from-adresse, j'ai du mal avec celui du haut et celui du bas. Désolé. Donc là, par exemple, le malloc ADDR qu'on avait là, c'est donc l'adresse retournée par notre malloc. Et notre malloc int, c'est quoi ? C'est la valeur retournée à cet adresse-là, ce qu'il y avait dans malloc. Donc là, on peut par exemple écrire 42 à cet endroit-là. On a le droit, c'est nous qui l'avons alloué. Mais là, c'est trop bien. On écrit 42. Mais là, donc, on a le droit de faire du C plus ou moins standard. Donc on peut free notre int. Donc là, attention, si on se trompe, ça s'accfole. Donc c'est malloc ADDR. Et donc là, si on regarde encore, on a notre malloc int, qui était ce qui avait cet endroit-là. L'implémentation de malloc derrière écrire notre 42, parce que voilà. L'idée derrière, tout ce qu'il faut voir là, c'est qu'en fait, on peut récupérer et créer un type C qui pointe sur une adresse de notre choix. C'est-à-dire n'importe laquelle. C'est-à-dire que ce truc-là, ça ne vient pas de Python ou de rien. Donc ça nous permet vraiment d'aller écrire ou lire plus ou moins à n'importe quel adresse si on connaît l'adresse que l'on veut taper. C'est plutôt sympa. Et enfin, pour finir, une bulletine de la libre standard Python, qui est la bulletine ID, qui retourne l'identité d'un objet. L'identité d'un objet, c'est quoi ? C'est le même objet qui a toujours le même ID pendant toute sa durée de vie. Et deux objets différents n'auront jamais le même ID. Implémentation détaille de ces pitons plutôt cool, c'est que c'est l'adresse de l'objet en mémoire. Normalement, on peut dire que ça fait tick. C'est qu'on peut accéder à l'adresse, on peut avoir l'adresse de n'importe quel objet Python. On est capable d'écrire à n'importe quelle valeur et de lire à n'importe quelle valeur dans notre adresse space. Donc en fait, on peut toucher à n'importe quoi dans les internals de Python, à partir de maintenant. C'est plutôt rigolo. Donc on va commencer avec un truc. Le truc, c'est la gestion de la mémoire par Python. Donc le référent scooter et le garbage collector. Donc tout ce qu'on a besoin de savoir, c'est que Python, comment il gère sa mémoire ? En tout cas, c'est Python. Il fait du référent scooting. C'est à dire qu'à chaque fois que, par exemple, vous avez une liste et que vous avez X, c'est égal à votre liste. La liste elle-même sait qu'il y a une référence VRL. Il y a un pointeur sur la liste. Si vous faites Y et d'égal à X, il y en a deux. Donc ça, c'est le référent scooter. Le référent scooter, tout ce qui fait, c'est quand il tombe à zéro. Il n'y a plus de référent sur les listes. Vous pouvez plus accéder à la liste. La liste est nettoyée. Et on peut observer ce référent scooter. Tout ce qu'on a besoin, c'est de savoir dans notre objet où est-ce qu'il est. Pour ça, on fait un petit peu de C. Donc bienvenue dans ces pitons. Object.h. Donc tout ce qu'on voit, c'est que le type pay object, quel type de base de piton, c'est composé d'un pay object head. Et dedans, il y a le head extra, qui est en petit dans les buts de standard. C'est pour du debug. Le obé réf compte, donc le référent scooter qui nous intéresse. Et enfin, le type, parce que tout objet est un type. Donc là, on voit directement que notre ref compteur il est au début de notre objet. Qu'est-ce que ça veut dire? Ça veut dire que si on accède à l'adresse directement d'un objet avec un C int, on va pouvoir récupérer un pointeur et donc un C int sur notre ref compteur. Donc comment on va faire ça? Comme c'était marqué. Je suis encore dans celui du bas. Donc là, on n'a qu'une liste. Et on a T underscore ref, qui est donc un int qui est représenté parce qu'il y a l'adresse de T. Donc à l'adresse de T, on a vu qu'il y avait notre ref compteur. Donc normalement, vu qu'on a notre liste, si on fait T underscore ref, on a un, parce qu'il y a une référence sur notre objet, c'est T. Maintenant, si on dit Y égal T, là on a Y et T qui pointent sur la liste. Et là, on accède en fait au nombre de valeurs qui pointent directement sur notre objet. Si on en supprime un. Donc là, j'ai accès à Y. Ça, c'est Y toujours. La référence sur T, elle est à 2. Donc en fait, c'est comme ça que le C piton va savoir combien il y a de pointeurs, donc de noms associés à un objet et comment il va savoir s'il doit cliner l'objet, donc le libérer ou pas. Ce qui est plutôt rigolo. Donc ça, c'est la première chose. C'est une des bases de la gestion de la mémoire de piton. Alors, maintenant le garbage collector. Parce que ça, c'est un cas simple. Et si on arrive à 0, on peut vous le montrer d'ailleurs. Là, j'ai Y à plat. Et le dernier, je l'avais nommé S. Là, plus de référence. Notre objet a été nettoyé. Il a été fri si on parle côté C. Maintenant, le garbage collector, c'est quoi ? C'est, par exemple, si on prend un objet A qu'on en crée 2 et qu'on fait juste pointer l'un vers l'autre. C'est-à-dire qu'on se retrouve avec une référence cyclique. C'est-à-dire qu'il y a A1 qui est une référence sur A2 et A2 qui est une référence sur A1. Donc vous voyez ça, par exemple. Si on exécute ça dans l'entrepréateur, donc c'est garbage. Et on tire garbage. Là, on a A1, par exemple. On a ref. Donc ref, qui est égal à 2 parce qu'en pointeur sur A1, il y a quoi ? Il y a le pointeur que nous, on a sur A1. Et il y a aussi A2.A qui est la même chose. Donc là, c'est par exemple si on dilite A1. On a quoi ? Il nous en reste une référence, celle de l'autre. Et si on dilite A2, le problème étant que A2, en fait, il a toujours une référence qui est celle de A1. Et A1 a toujours une référence qui est celle de A2. C'est-à-dire qu'on a un cycle, et nous, on ne peut plus accéder du tout à l'objet. Donc là, en fait, on pourrait dire, les deux objets sont perdus et on ne peut rien faire. Ils ne sont jamais libérés. Ça prend de la mémoire. Mais c'est là que ce qu'on appelle le garbage collector arrive. Donc j'essaie qu'elle module pour gérer le garbage collector à la main. Et le garbage collector, en fait, ce qu'il va faire, c'est qu'il va prendre tous les objets et il va regarder tous les objets auxquels nous on ne peut plus accéder et enlever des références. Il va nettoyer tout ce dont auxquels je ne peux plus accéder. Il a collecté quatre objets et si on regarde nos références, c'est égal à zéro. Donc ça, c'est le garbage collector de piton qui permet comme ça de récupérer, de nettoyer les références sur des objets auxquels on n'a pas accès. Donc là, on a fait de la lecture. On a vu que les rêves coon, c'est génial, ça marche, le garbage collector marche. Maintenant, qu'est-ce qu'il se passe si on modifie l'état nous-mêmes ? Donc getref, c'est la fonction qui fait ces teams info madresse de ID21. Je l'appelais getref. Et là, je récupère juste une référence sur une liste, donc rien de bien méchant, sauf qu'on va changer à la main la rêve-value. Donc qu'est-ce que ça fait ? Donc là, on a getref qui est égal à 1. On a t qui pointe sur notre liste et t2 qui pointe sur notre liste. Si on en supprime 1 des 2, qu'est-ce qu'il se passe ? On en supprime t2. On a notre ref, pardon, on a notre t qui est toujours là. Le problème étant c'est que notre t underscore ref est égal à 0. C'est étonnant, ça a donc noté. Qu'est-ce qui s'est passé ? En fait, on a une référence qui tombe à 0. Donc on nettoie l'objet. Le fait est que l'objet n'est pas vraiment free parce que Python gère des listes en interne qui va stocker pour lui. Mais il met quand même la size à 0. C'est-à-dire que là, on a mis la size à 0 parce que l'objet, il n'y a plus de référence dessus. Vu que le truc est égal à 0, nous on a une référence, on devrait pas avoir le droit. Donc là, il était mis dans une free liste où toutes les listes, certaines de listes sont stockées free s'il y a besoin pour des accès rapides. Et ce qui est marrant, c'est que si on crée une nouvelle liste, voilà, je crée une nouvelle liste X, ça va prendre cette free liste, la première de la free liste et ça va l'utiliser à la place. Donc là, en fait, T, c'est une référence vers un objet qui, enfin, vers une liste qui n'existe pas pour Python. Et donc en fait, on peut comme ça avoir des références à 0, on ne devrait pas, et voir qu'en fait, le système des free lists, comment il est utilisé dans Python, de, je réutilise les anciennes listes parce que free et malo, ça, c'est plutôt rigolo. Et là, par exemple, si je commence à faire des choses, genre, est-ce qu'il va aimer ? Ouais, ça va. Il n'a pas craché. Bon, on a de la chance. Donc voilà, ça, ça montre que on a des reuse de listes et des choses comme ça qui sont plutôt cool. Maintenant, on va parler du module, enfin, du type tupple, pardon. Donc tupple, que nous dipitons, c'est que c'est une imbutable sequence type. Est-ce que on peut changer ça ? C'est quoi un tupple derrière ? Est-ce que nous, vu ce qu'on peut faire, voici ce dont on a besoin de savoir sur un tupple. Un tupple, c'est un pay-object var-head. Donc un var-head, c'est quoi ? C'est une id-head qu'on a vu de tout à l'heure. Plus une size. Donc en gros, on a le ref-count, le type, la size. Et derrière, il y a une liste de pointeurs de pay-object. Donc tout ce qu'on a besoin de savoir, c'est qu'avant nos pay-objects, on a juste 3 size-t. Avec ça, qu'est-ce qu'on peut coder ? On peut coder un tupple-copy. Donc, qu'est-ce qu'il y a besoin de savoir là ? Le c-type-size-t, c'est la taille d'un int, d'un piton. Donc l'offset, c'est là qu'on va commencer à copier. Donc c'est, on prend notre objet et on se met derrière le ref-count, derrière le type et derrière la size. Et à cet endroit-là, on va en fait juste copier un tupple dans un autre. Donc ça va permettre de réécrire des tupples de façon simple et de façon totalement illégale. Donc c'est type-move qui est je fais une copie, c'est tout. Alors la question, c'est qu'est-ce que ça nous permet de faire ? Par exemple, on va faire une modification de tupple et on écrit en fait le premier dans le deuxième à partir de la moitié. On va faire une modification de tupple. Très bien. Si on essaye ça, qu'est-ce que ça nous donne ? Ah, raté. Ah oui, il faut extrêmement très raté. Donc là, on a quoi ? Avant, on a bien nos deux tupples A, A, A, B, B, B. Et là, on réécrit X. Et si on regarde le code, dans le code, j'ai pas changé la référence, tient rien. On a fait une modification en place. Le problème, cet exemple-là, donc, on fait à peu près la même chose que notre deuxième tupple, il a une référence sur une liste. Par exemple, qu'est-ce qui se passe ? Ah, super. Là, on a X1, on a X2 et là, on supprime X2. C'est-à-dire qu'on va enlever toutes les références sur la liste. On va se retrouver avec le même problème que tout à l'heure. C'est-à-dire que là, on a un objet avec un rêve coute à zéro, ce qui n'est pas normal, ce qui n'est pas bien. Et donc, on peut rejouer ça à repris les références. Donc ça, c'est moyen. Donc, ce qu'on peut faire, c'est faire une version que je n'ai pas mis dans les slides, mais on peut, par exemple, coder une version qui va, en fait, si on regarde, ce qui est en plus, c'est le four object in source. On va incrémenter à la main le rêve couteur, dire, eh, on a une nouvelle référence vers l'objet. Comme ça, c'est toujours illégal de modifier un tupple, mais c'est un peu moins illégal. Donc maintenant, on peut modifier des tupples. La question, c'est qu'est-ce qu'on peut faire ? Il va partir sur des choses qu'on va pouvoir modifier maintenant, et on va pouvoir découvrir encore plus d'internals de pitons. On va projeter au coeur des fonctions. Donc, les fonctions, c'est ce qui nous permet d'exécuter du code. Donc là, on a une lambda. C'est la lambda qui a x avec ceci, x fois 2. Je vous présente un nouveau module, le module 10. Qu'est-ce que c'est que le module 10 ? C'est le désassembleur de pitons. Donc, par exemple, si on désassemble ici la folie de notre lambda, on voit le code, on va charger la valeur, enfin, le nom x. Très bien. On va charger la valeur 2. En fait, c'est ce qu'on voit, si je pointe du doigt. En fait, on va chercher x. On va charger 2. On va multiplier les 2 et on va retourner la valeur. Ça paraît plutôt simple. La question, c'est comment ça marche en intérieur ? Et surtout, les deux questions, c'est qu'est-ce que c'est que ce 0 là ? Qu'est-ce que c'est que ce 1 là ? Alors, on va commencer par jouer avec la valeur 2. Donc pour ça, en fait, on va aller plonger ce type. Donc, on va aller dans fin const à plat, point paille. Et donc, oops, j'ai oublié le tiraill. Yep. Et donc, en fait, on voit que, par exemple, on a notre f. f.funk underscore code. C'est là où on stock les informations sur le code de la fonction. C'est-à-dire les informations qu'il faut vraiment pour exécuter la fonction. Et dedans, on a un truc plutôt cool. Const. Et ça, c'est quoi ? C'est toutes les constantes utilisées par la fonction à un moment. On regarde ici. Là, on avait bien, je l'ai plus là. On avait bien, par exemple, l'autre const de 1. 1, c'est quoi ? C'est l'offset. Art. C'est l'offset dans le tuple. C'est note 2. Donc la question, c'est si on modifie ce tuple-là, est-ce qu'on peut modifier comment fonctionne la fonction ? Il y a juste à essayer. Donc, déjà, je vous prouve que quand même, la fonction, à un moment, elle marche. Ok. Si maintenant, ce truc-là, je le modifie 10. Le tuple 10, et on veut partir de l'offset 1. Notre const, maintenant, c'est ça. Et notre fonction, qu'est-ce qu'elle fait ? Elle multiplie par 10. Wow. Ça, c'est fun. Donc maintenant, on sait comment sont stockées les constants dans une fonction. Et on peut modifier n'importe quelle constante comme ça. Pourquoi pas ? Maintenant, la deuxième question, c'est, on a ça pour les constantes, pour le X. D'où sort ce X ? Parce que là, on a bien vu qu'il y avait pas de X. Alors pour ça, je vais commencer par quelque chose. C'est, on voit qu'il fait un load, ici, on voit qu'il fait un load const, un load const de X. Ok. Alors la chose, c'est qu'on peut appeler, bien évidemment, comme on est en piton, on peut appeler F2X-2. Ça, on a le droit. On peut s'autoriser, on peut, on utilise les noms. Maintenant, si on va chercher à l'endroit, ouf, il y a ces noms-là, donc c'est dans co-varname, là où il y a les noms, on voit que, ben oui, il y a le nom X qui est utilisé et qui est en zéro. On avait là, Lofast-2.0-CX. C'est cool. Donc ça, si on le modifie à son tour, tu peux le copier de ça. On va prendre un nom plutôt cool, on va prendre var. Là. On a dit, à partir de 0. Et maintenant, si on rappelle notre fonction avec X-4, ah non, la fonction elle ne prend pas de X. Par contre, la fonction maintenant, elle peut prendre variable var. C'est pas mal. Et donc, ça semble notre fonction F. Ah, pardon. C'est bien, la fonction qui prend une variable s'appelle var et qui la multiplie par 10. C'est toujours la même fonction qu'il n'y a pas touché. Donc voilà. Donc ça, ça montre un peu comment, en interne, il stocke les valeurs dont il va servir. Donc, les noms dont il va servir, c'est-à-dire que s'il faisait des accès à des globales aussi, on pourrait modifier les globales qu'il va chercher, ce qu'il ne faut absolument pas faire. On peut les chercher, par exemple, et on peut modifier, par exemple, les fonctions. Si on regarde le code, la fonction F qui fait rien, F ne fait absolument rien. Le truc, c'est que F.funconderscorecode. Conderscoreconst. On peut le modifier aussi. On peut faire que la fonction qui ne retourne rien maintenant soit la fonction qui retourne 2. Voilà. Je ne vais pas le faire, parce que ça va prendre du temps et il y a une autre chose. Donc ça, c'est co-const, ça, c'est vername. Et enfin, les clôtures. Donc les clôtures, en anglais, clôtures, c'est quoi ? La fonction dans d'autres fonctions. C'est super mal expliqué, mais bon. Par exemple, on a la fonction reten, qui va générer une fonction qui fait, qui retourne toujours la même valeur. Par exemple, la fonction reten, si on l'appelle avec 10, ou avec 42, ça va toujours créer la fonction qui retourne toujours 42. La question, c'est comment s'est stocké ça en interne ? Donc déjà, vous pouvez voir le code en dessous. Ça fait juste un blow des rêves de N et ça retourne la valeur. Si on prend le code, donc c'est funclosure. Alors, appela, funclosure, super. Donc voilà. C'est quoi le nom de la fonction ? C'est ret 42. Ret underscore 42. Là, on a un truc, c'est pas dans le code de la fonction, c'est dans la, enfin, c'est pas dans le fun underscore code, c'est dans la fonction elle-même pour des raisons techniques. Et on a un truc qui s'appelle funt underscore closure. C'est un topol, un topol de celles. Une celle, c'est quoi ? C'est juste un truc. Ah, euh, pardon, contents. C'est en fait le moyen capiton de créer, comme ça, des closures et en fait de pouvoir les réunir. Enfin, de pouvoir avoir le même code qui utilise des closures différentes. C'est-à-dire que, par exemple, si on faisait reten, x égal, la, par exemple ça, c'est la fonction qui retourne toujours deux. La seule différence entre les deux, c'est la clôture, la closure. C'est-à-dire que tout le reste, tout le code est exactement la même chose. On n'a recréé pas un objet code et tout, c'est super pratique. Et ce truc-là, bien évidemment, on peut aussi le modifier. Donc si on va le modifier, pour tester, c'est quand même, donc ret underscore 42. Ça retourne toujours 42. Et si on fait quelque chose comme tu peux le copier de ça. Je ne suis pas très inspiré, je m'excuse. Alors là, moins 1. Pourquoi moins 1? Parce que c'est une cell, l'objet. Ce n'est pas un tupple. Et une cell, ça n'a pas de taille. Donc si ça n'a pas de taille, à la place de la taille, on a la valeur. Donc en fait, c'est juste qu'il faut réécrire la taille et pour réécrire la taille, on a créé la fonction qui retourne le. Voilà. Donc ça, c'est les 3 trucs rigolos qu'on peut modifier assez facilement avec de la réécriture dans les fonctions. Et ça permet de comprendre un peu comment en Python, sans créer les constantes, etc. sont gérées les constants dans les fonctions. C'est-à-dire que si vous avez une fonction qui est 6 fois la constante 2, il n'y a liée qu'une fois dans votre code. Elle est à un endroit et c'est super clean. C'est plutôt cool. Combien de temps il me reste? Par curiosité? 8 minutes. Parfait. On va jouer maintenant avec les types. Parce que les types, c'est rigolo donc question une, qu'est-ce qu'un type? C'est ça. C'est l'int. Donc, il y a des choses qu'on n'a pas besoin de savoir, des choses qu'on a besoin de savoir. Ce qu'on a besoin de savoir, c'est son nom. Donc ça, c'est pas in-type. Super. C'est quoi? C'est un objet variable. Le type d'un type, c'est type. Jusqu'à là, c'est simple. Le nom, c'est int. Ça, c'est la taille de votre objet. De votre objet. Rien de plus. Et derrière, c'est toutes les fonctions qu'on va utiliser par exemple, si on veut printer notre int, ça va être cette fonction-là qu'on va appeler. Si on veut comparer notre int à autre chose, on va appeler cette fonction-là. Il y a quelques trucs qui sont assez spéciaux. Il y a par exemple, cela, qui, en fait, permettent de voir si votre objet est peut-être un représenté comme un entier, as a number. Il y a as a sequence qui permet de savoir si c'est un itérable, j'aurai une liste ou quelque chose comme ça, et as mapping pour voir si on peut s'en servir comme dictionnaire. Et donc ça, c'est comme ça que votre type est fait. Il y a un patch de fonctions, c'est-à-dire que vos fonctions, quand on va appeler, par exemple, le print sur un int, on va aller dans type de int, on va prendre la fonction qui a cette offset-là, donc int print, et on va l'appeler. Qu'est-ce que ça donne si on bosse à partir de ces types ? Ça, c'est des structures ces types. C'est comme ce qu'on a fait tout à l'heure avec le cint, sauf qu'on en met plusieurs. Et là, on a bien vu que notre pay object, c'était un ref-count et un obj type, et que nos pay variables, donc un truc variable, c'est quoi ? On va faire des choses un peu plus propres quand on réécrit des offsets un peu louches dans nos types. Donc si on prend, par exemple, ce truc-là, qu'est-ce qu'on a ? On a T qui est un tupple, et on a TM qui est le mapping, donc l'objet autour de notre tupple. Et on a pareil pour notre int. Donc ça, si déjà je lance ça, ça ne sera pas mal. Donc on a T. On a TM auquel on peut récupérer, par exemple, sa size. TM, on peut récupérer son type. Et alors, ce truc-là, si on regarde, est-ce que c'est un tupple ? Ouais. Là on voit qu'en fait, l'obétype de notre objet c'est l'adresse de tupple, donc son type. Et on a pareil pour les ints si on veut. La question c'est qu'est-ce qu'il se passe si on le modifie ? Mais si on le modifie n'importe comment, ça va sec fault. Par exemple, si on dit que notre type, par exemple, l'obétype de notre TM, c'est égal à un dict. Le truc, c'est que derrière, on n'a pas la représentation du dict, on n'a rien, c'est pas un dict. On va essayer de le compter, je ne savais même pas que ça marchait. On va essayer avec autre chose. Vas-y. J'ai fait quoi ? Oui, mais t c'est le... Bah vas-y, hop là. Ce qui est normal. Mais là, on a appris un truc super rigolo. C'est que on a quand même accès à notre t, qui était un tupple. C'est moins impressionnant que le tupple, mais on a vu qu'on pouvait quand même essayer de travailler dessus. Si on recommence avec notre t, hop là, notre x. Si maintenant, par exemple, notre t, point ob, underscore type, si on dit que c'est un int, allez, maintenant, t, un int. D'après vous, qu'est-ce qui se passe ? Quelque chose ? Ça crache encore ? Je vous ai promis des craches. Allez, ça marche parfaitement. Pourquoi ? Parce qu'en fait, le truc, c'est que notre int, ça a quoi ? C'est un ref-count, un tip, une valeur. Et de l'autre côté, on a notre tupple qui a quoi un ref-count, un tip, un risque de notre tupple, donc 5. Et là, on peut y aller, ça marche. C'est-à-dire que aucun problème, c'est devenu un int qui fonctionne très bien. Mais maintenant, si on prend plutôt notre x, et si notre x, on dit que maintenant, bon bah, xm, pardon, xm.ob, underscore type. Allez, on dit que c'est un tupple. Donc là, on a un tupple. Si on refait le même mapping, on a un tupple de taille 42. Ce qui va se passer, et qui va accéder à l'adresse. Ça marche pas ça. Par contre, le truc rigolo, qui est super intéressant, c'est que si on fait la même chose, là, pardon, .ob, underscore type, et après, c'est égal à un tupple. On a quand même accès, donc sur notre x, qu'on va pas print, on a accès aux fonctions, ce qui est logique. C'est-à-dire que notre int, on peut aller accéder au 6e élément de notre tupple, alors que c'est un int. Ça va faire quoi ça ? Ça va aller cracher. Qu'est-ce qui se passe ? Ça marche. Ah, pourquoi ? Parce que ça, c'est une exception de 4. Je n'ai pas pris au hasard. En fait, on a notre int. Très bien. Dedans, on a notre ref-count. On a notre type. On a quoi derrière ? On a notre valeur. Et derrière, ce qui se passe, c'est qu'on a un autre int. Parce qu'en fait, tous les int entre .5 et .127, si je n'ai pas de bêtises, sont dans une liste contigu. Donc on sait qu'après 42, il y a 43. Et qu'en fait, le 0e c'est le ref-count. Le 1er, c'est le type . Donc c'est ça. Le 2e, c'est quoi ? C'est la valeur. Enfin, oui, c'est ça. Le 3e, c'est le ref-count de l'objet qu'il y a après. Donc le ref-count de 43. Et le 4e, c'est le type du objet qu'il y a après. C'est int. Et donc là, on peut se balader en mémoire. Et tant qu'on tombe sur des pointeurs vers des objets valides, on peut aller faire des trucs. Donc c'est rigolo, hein. Ça, ça marche. Et ça, ça marche pas. Donc voilà. C'est juste pour montrer que c'est vraiment votre type. C'est le pointeur type qui définit quelle fonction vous pouvez appeler et comment ça va réagir derrière. Ce qui est plutôt cool. Donc voilà. Est-ce que j'ai le temps pour un bonus ? 2 minutes. J'ai pas le temps pour un bonus. Juste un truc, c'est les bulletins. Par exemple, si on arrive à B.S. La fonction absolute, qui permet de faire ce genre de choses, derrière, c'est du C. C'est vraiment du code en C. C'est pas du code piton parce que ça prendait trop de temps d'avoir ça en piton. La question, c'est comment on fait le rapport entre le C et le B. En gros, c'est un objet qui va permettre à partir du piton d'appeler du C. Tout ce qui nous intéresse c'est notre objet. Il a un truc qui s'appelle MML qui est en fait des informations sur la méthode qu'on définit. Il y a son nom, par exemple. Et il y a la méthode qui est en fait juste un pointeur de fonction. Il n'y a vraiment rien dans ce truc-là. Et le seul truc qui nous intéresse, le seul truc qui va aller vraiment être très intéressant, c'est le pointeur vers la fonction auquel on veut accéder. C'est tout. Alors, les infos sur MABS et Mbine. Et si on sert de ça pour... Alors, si on sert de ça, qu'est-ce qui se passe ? Je ne sais plus. C'est celui-là. Là. Pardon. Thierry. MABS. Donc ça, c'est la fonction MBS. Ça, c'est la fonction BIN. Et la fonction MBS, on peut dire son. Alors, je ne les connais pas par coeur. M... Pardon. M underscore ML. Pardon. Donc là, en fait, on a un truc qu'on voit qu'il y a un pointeur, parce que c'est des pointeurs, etc. À partir de ces tailles pour aller toucher des pointeurs, c'est contents. Voilà. Il faut le savoir. Il l'a d'où qu'une fois. Là, on a le contents. Et là, par exemple, si on fait ML underscore MET, ça, c'est l'adresse. C'est vraiment l'endroit en C où on va aller taper. Et si on prend ça, moi, je la flemme. Hop, là. Et qu'on prend la place Mbine. Donc là, abs. C'est toujours la fonction abs. Voilà. Si je l'appelle avec 10. Ah, pardon. Voilà. C'est-à-dire que le C derrière, en fait, c'est vraiment le C qui est intéressant, qui va aller transformer les objets et tout. Mais sinon, c'est pas du tout la même fonction. C'est-à-dire que j'ai pas juste fait abs et galmine. Derrière, c'est deux choses différentes. Et voilà. Non, c'était pas ça que je voulais faire. C'est un égal égal. Bon. C'est pas grave. Vous avez compris ce que je voulais dire. Et donc, c'est plutôt rigolo de voir que c'est des pointeurs que je ne l'ai pas fait parce qu'il faudrait des notions en plus, etc. Vous pouvez carrément créer du code. Créer du code C, l'injecter et le faire exécuter depuis Python. Donc c'est plutôt rigolo. Et si vous voulez vraiment que vous amusez, il y a moyen de faire des choses très drôles avec ça. Sinon, derrière, c'est tout. Donc j'espère que ça vous amuse comme ça m'amuse. Et j'espère que vous avez découvert ou deux trucs sur comment c'est Python, ça marche derrière. Pourquoi il y a des pointeurs partout et quels trucs sont importants pour faire quoi. Et voilà. Si vous n'avez pas peur de l'assembleur, j'injecte du code assembleur à la main et j'exécute depuis Python. J'ai fait un article de blog sur ça. Ça permet de faire des trucs vraiment cool et de créer des choses dans Python qui ne devraient pas exister.