mardi 14 février 2023

Il y a autre chose que les classes en Python

 Le langage Python offre un éventail de dispositif pour structurer et organiser les données.

ci dessous un aperçu: 


Les slices. 

Ainsi déjà avec une simple donnée string, il est possible de donner un nom à des tranches de chaine pour simplifier les manipulations:


Les tuples nommés.

Ils ne sont pas toujours appréciés à leur juste valeur pourtant ils permettent des simplifications :

Attention, un tuple n'est pas modifiable ! 
Il est possible de créer des tuples nommés à partir d'une structure iterable comme une liste ou un dictionnaire. Pour ces derniers l'opérations inverse est possible.
 



Un tuple nommé est très utile pour présenter le contenu d'un flux comme celui d'une requete SQL

Sans le tuple nommé, pour accéder au nom de l'acteur il faudrait indiquer le nom de la colonne:

row[1]


Avec un tuple nommé : On manipulera le résultat par le nom de la colonne.


Les classes vides et le dispositif  Simplenamespace.

Quand on désire construire une classe dynamiquement pour n'utiliser que ses attributs, la solution la plus connue est de créer une classe vide (class A:  pass). Il existe pourtant une autre solution:  simplenamespace.



Ce système est utilisable pour convertir à la volée, une ligne d'un fichier JSON:

Exemple : avec une fonction object_hook


Comme c'est un objet, il est modifiable.

Et pour les dataclasses ?: Elles feront l'objet d'un prochain billet, car elles sont très puissantes et elles sont de plus en plus utilisées.


samedi 11 février 2023

Python: fonctionnement du modèle objet

 Python propose un modèle objet assez simple par rapport aux autres langages. Il se situe à mi-chemin entre le dispositif mis en place pour Perl et celui plus sophistiqué de Java.

En Python, il n'y a pas à proprement parlé d'attribut privé. Il existe la notion d'attribut protégé qui s'obtient en préfixant  le nom de l'attribut par deux  '_'   , exemple:  __monAttribut .

Un attribut protégé est toutefois accessible par l'ajout du nom de la classe , exemple :  _maclasse__monAttribut . Cette protection est donc toute relative.

Comment Python recherche une méthode ou un attribut.

Pour connaitre le cheminement, il est possible de redéfinir ses propres méthodes.

Celle à implémenter dans une classe sont: 

    def __getattribute__(self, attr):
        print(f"attribut demandé : {attr}")
        return super().__getattribute__(attr)
    
    def __getattr__(self, attr):
        print(f"attribut demandé non trouve : {attr}")
        return super().__getattribute__(attr)
    
    def __setattr__(self, attr,val):
        print(f"attribut a changer : {attr} avec {val}")
        super().__setattr__(attr,val)          

Recherche d'un attribut ou d'une méthode.


En  faisant quelques essais, on est capable de dresser le schéma suivant: 




Quand un attribut ou une méthode est recherché dans l'instance d'un objet, la méthode interne __getattribute__ est appelée.
  • En cas d'échec de la recherche au sein de l'objet, une recherche est relancée au niveau de la classe elle même pour retourner une attribut de classe par exemple. 
  • En cas d'échec la methode __getattr__ est sollicitée en dernier recours.

Mise à jour d'un attribut.


Le circuit est simplifié: 


Quand une demande de mise à jour est lancée, la méthode __setattr__ est activée, si l'attribut n'est pas trouvé au sein de l'objet , la création de l'attribut se fera au niveau de l'objet.

Ecarts de comportement.

Cette illustration permet de comprendre pourquoi il est possible de créer des attributs à la volée. Il explique aussi le comportement de Python face aux variables de classe ou aux attributs protégés.
Dans ces deux cas de figure, un nouvel attribut sera crée interférant avec les autres. 

Illustration:  Une classe avec une variable de classe et un attribut protégé


Jusque là tout va bien:
Apres quelques manipulations de la variable de classe: 

Idem pour l'attribut protégé:



Après ces manipulations, l'objet est un peu en vrac. Aussi pour laisser les choses dans l'ordre, deux règles sont à observer:

  • Ne pas manipuler une variable de classe par le biais des objets instanciés.
  • Ne pas manipuler directement les attributs protégés