@adri1 : dans le mille c’est le cas de le dire. Merci pour la précision sur
objets Python = Rc<RefCell<T>>
si tu as d' autres points de comparaisons sur Rust ou en Asm ça m' interesse énormément.
Il n’y a pas forcément grand chose d’intéressant à dire sur le modèle mémoire de Python. Cela dit, le fait que les objets sont en gros des Rc<RefCell<T>>
plutôt que des Arc<Mutex<T>>
explique la nécessité du GIL: leur design est trop fragile pour garantir que leur manipulation est thread safe. Un autre parallèle, beaucoup plus immédiat, est que les dictionnaires en Python (qui sont présents partout) sont en gros des HashMap<K, V>
et demandent que les K
soient hashables (ce qui rejoint l’erreur que tu as mentionnée plus bas).
As tu des conseils de dissection pour aller grater là où c’est le
plus interessant ? j’ai remarqué locals, globals, gc, inspect, ctypes peut-être stuct.
T’as des trucs assez variés qui touchent à des choses assez différentes. gc
est probablement le plus proche de ce que tu as déjà abordé dans ce sujet, il donne accès au garbage collector. Il s’occupe de nettoyer les objets dont le compteur de référence est tombé à 0, et surtout a des heuristiques pour détecter les cycles de références qui ne sont pas joignables de l’extérieur. La comparaison avec Rc
s’effrite ici d’ailleurs, puisque le modèle d'ownership de Rust couplé à Rc
ne permet pas d’éliminer un cycle de Rc
(d’où la nécessité de Weak<T>
). Le fait que Python utilise un GC (plutôt que bêtement virer les objets dès que leur nombre de référence tombe à 0 comme le fait Rc
) est uniquement pour éviter les fuites lorsqu’il y a un cycle de référence.
locals
, globals
et inspect
te permettent de jouer avec les mécanismes du langage plutôt que de son implémentation, pas sur que ce soit ce que tu cherches.
ctypes
et struct
seront utiles pour t’interface avec du code C (ou qui respecte l’API C), tu pourrais avoir intérêt à fouiller du côté de l’API C offerte par Python.
Un truc qui me parait plus dans la ligné directe de ce que tu veux faire est le module dis
qui te permet de manipuler le bytecode interprété par la machine virtuelle CPython (l’implémentation standard de Python). Le code Python est compilé sous forme de bytecode (et mis dans le dossier __pycache__
que tu as sûrement vu trainer). C’est ce bytecode qui est interprété plutôt que le code Python lui-même (pour des raisons de perf).
Je vais essayer de recréer un dict customisé, j’ai eu des erreurs du genre
TypeError: unhashable type: 'dict’. Un article de blog qui va en profondeur sur ce genre d' experimentations ?
Pas facile de donner plus de détails sans un code, mais ton problème est que les clés des dictionnaires doivent implémenter __hash__
(pour pouvoir construire la hash table qui permet le lookup en temps amorti constant), autrement dit être hashable. De manière similaire, pour HashMap<K, V>
, tu as besoin de K: Hash
(et Eq
mais c’est un choix de Rust).
Or, les instances de dictionnaires ne sont pas hashable. Le message d’erreur est pas terrible d’ailleurs, parce que le type dict
(qui est une instance de type
) lui est parfaitement hashable. De manière générale, les mutables ne sont pas hashable en Python (tes propres types peuvent l’être si tu veux par contre), je pense pour éviter de casser l’attente id(a) == id(b)
implique hash(a) == hash(b)
(avec des valeurs mutables, ça va dépendre de ce qui se passe entre les deux calculs de hash comme on s’attend à ce que le hash dépende de la valeur).