IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Constructeur classe dérivée à partir d'objets parents


Sujet :

Python

  1. #1
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut Constructeur classe dérivée à partir d'objets parents
    Bonjour à tous,
    Juré, craché j'ai fait une recherche sur ce forum avant de poster.
    Je vais essayer de faire simple:
    J'utilise l'objet Element de la librairie lxml (bonne librairie, au passage).
    Cet objet en l'état ne convient pas complètement à mes besoins, il lui manque une donnée 'poids' que je calculerai en utilisant certaines règles.
    L'idée naturelle est donc de construire mon objet MyElement en le dérivant de Element, et de rajouter une donnée 'poids'.
    Problème: Je veux instancier mes objets à partir d'objets EXISTANTS de type 'Element'.
    Je ne sais pas comment faire avec mes connaissances actuelles.
    Bien sûr je peux toujours 'agréger' sans dériver, définir MyElement comme ayant une donnée membre de type Element et une donnée poids et puis passer les deux arguments à __init__, mais cette solution je ne m'y résoudrai qu'en dernier recours, pour beaucoup de raisons (ne pas réécrire l'itérateur, etc.. etc..)
    Je recherche donc une solution du type:
    class MyElement(etree.Element):
    ..........
    Quelqu'un a une idée ?
    Merci.
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  2. #2
    Membre Expert Avatar de pacificator
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 074
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 074
    Par défaut
    Salut Zavonen,

    As-tu tenté de modifier la classe de ton objet?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    >>> class A(object):
    ...     def __init__(self, x):
    ...         self.x = x
    ... 
    >>> class B(A):
    ...     def ecrire(self):
    ...         print self.x
    ... 
    >>> obj = A('toto')
    >>> obj.__class__ = B
    >>> obj.ecrire()
    toto

  3. #3
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    Bonjour Pacificator,
    Merci pour ta réponse.
    Dans mon cas cela ne fonctionne pas. En effet, je ne veux pas toucher à la classe de base. Pas question donc de modifier le __init__ de Element.
    J'ai résolu mon problème de la façon suivante. On peut définir pour tout 'tag' des attributs ad libitum (mais seulement de type litteral). Bref, pour mes calculs je peux faire des conversions et sauver les résultats sous forme de string dans un attribut du tag.
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    from lxml import etree
    root = etree.Element("root")
    root.set("poids",unicode(1))
    root.set("poids", unicode((int(root.get("poids"))*2)))
    print root.get("poids")
    Bon, mais ce n'est pas 'clean' et cela ne répond pas à ma question.
    Je te passe un message perso bientôt.
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  4. #4
    Membre émérite
    Homme Profil pro
    heu...
    Inscrit en
    Octobre 2007
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : heu...

    Informations forums :
    Inscription : Octobre 2007
    Messages : 648
    Par défaut
    J'ai pas très bien compris, est-ce que ceci marcherait comme tu le voudrais ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    >>> class Foo(object):
    	def __init__(self):
    		self.arg1=5
     
     
    >>> class Foo2(Foo):
    	def __init__(self):
    		super(Foo2,self).__init__() #apelle la méthode __init__ de Foo et l'applique sur cette instance (grossièrement)
    		self.arg2=6
     
     
    >>> a=Foo2()
    >>> a.arg1
    5
    >>> a.arg2
    6
    >>>
    Ca nous permet de surcharger une méthode, tout en utilisant également celle de la classe parente.

  5. #5
    Membre expérimenté Avatar de alexdevl
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    265
    Détails du profil
    Informations personnelles :
    Âge : 56
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Avril 2007
    Messages : 265
    Par défaut par A.__init__(self)
    Bonjour,
    Est ce que la forme (très courante) d'instanciation peux convenir ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class A :
        def __init__(self,param_x):
            self.x=param_x
            
        def affiche(self):
            print self.x
            
    
    class B(A):
        def __init__(self,param_x_pour_A):
            A.__init__(self,param_x_pour_A)
            
    b=B(5)
    b.affiche()
    Alex

  6. #6
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    Hélas, aucune de vos propositions ne peut me convenir.
    je souhaite avoir une instanciation de la classe dérivée à partir d'un objet (déjà instancié) de la classe parent.
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  7. #7
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    J'ai une solution si la classe de base est du nouveau type:
    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class A(object):
        def __init__(self, x):
            self.a=x
    class B(A):
        def __init__(self,X,y):
            dico=X.__dict__
            dico["poids"]=y
            self.__dict__=dico
     
    X=A(1)
    Y=B(X,2)
     
    print Y.poids
    print Y.a
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  8. #8
    Membre émérite
    Homme Profil pro
    heu...
    Inscrit en
    Octobre 2007
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : heu...

    Informations forums :
    Inscription : Octobre 2007
    Messages : 648
    Par défaut
    Ben je trouve justement que les super-objects sont tout à fait approprié... Dans ton exemple, en gros, tu voudrait que l'instance de la classe fille, récupère les attributs et les méthodes d'une instance de la classe parente...
    Et bien si une classe B dérive de A, et qu'aucune méthode n'est surchargée, B() aura tous les attributs, et méthode de A(). Sauf que si on veut que B() ai les même méthodes que A() mais avec un paramètre en plus déclaré dans le constructeur, on utilise un super-object:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    >>> class Foo(object):
    	def __init__(self,x,y):
    		self.x=x
    		self.y=y
     
     
    >>> class Foo2(Foo):
    	def __init__(self,x,y,z):
    		super(Foo2,self).__init__(x,y)
    		self.z=z
     
     
    >>> a=Foo2(1,21,321)
    >>> a.x
    1
    >>> a.y
    21
    >>> a.z
    321
    >>>
    Doc sur super()

  9. #9
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    @n.tox
    Tu as raison mais les exemples que tu donnes, sont construits à partir de classes 'jouets' pour lesquelles les données membres sont connues et peu nombreuses.
    Moi je dérive d'une classe complexe, et je ne connais pas la liste de tous les attributs des objets (et d'ailleurs d'une certaine façon je m'en moque).
    Mais tous ces attributs sont mémorisés dans la donnée unique __dict__, je n'ai donc qu'à recopier cette donnée et tout le monde est au rendez-vous.
    Autrement dit mon exemple ne se complexifie pas avec des objets (très) complexes, le tien si.
    En fait j'ai fait un peu rapide. J'aurais dû faire une copie de __dict__ pour ne pas induire d'effets de bord. Avec mon exemple, un objet de type A après avoir instancié un objet de type B se retrouve lui aussi avec un poids. Mais pour résoudre mon problème cela n'a aucune importance.
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  10. #10
    Membre émérite
    Homme Profil pro
    heu...
    Inscrit en
    Octobre 2007
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : heu...

    Informations forums :
    Inscription : Octobre 2007
    Messages : 648
    Par défaut
    J'avoue ne pas comprendre ce qui te gène... la méthode que j'ai indiquée est indépendante du nombre d'attribut ou de méthodes, il peut y en avoir 100 000 que ça n'a pas d'importance.

    Le plus important, c'est que tu sois parvenu au résultat désiré. Je reste toutefois persuadé que la méthode que j'ai employé, est plus "pythonesque", plus courte, et produit exactement le même résultat, peut-être à tort, je pense pas mais... Si une tierce personne pouvait confirmer/dementir mes dire, cela me conforterai (ou non) dans mes pensées .

  11. #11
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    Le constructeur de ta classe de base a deux paramètres x et y. Tu reprends ces paramètres dans la classe dérivée.
    Que se passerait-il s'il y en avait 100 ?
    S'il y en avait un nombre inconnu ?
    En plus tu n'instancies pas à partir d'un objet existant de la classe mère mais en fonction des paramètres du constructeur de la classe mère, ce qui n'est pas tout à fait la même chose. Moi je veux que l'objet dérivé recopie les données membres de son modèle quel qu'en soit le nombre et quelles que soient leurs valeurs, sans connaitre ni l'un ni l'autre.
    avec ta méthode tu serais obligé de faire:
    b=Foo2(a.x1,a.x2, ..... , a.x100, y)
    A supposer que tu connaisses le nombre des données membres et leur nom.
    Moi, je ne veux même pas les connaitre parce que j'utilise seulement certaines fonctionnalités de l'objet (que je connais parfaitement celles-là).
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  12. #12
    Membre émérite
    Homme Profil pro
    heu...
    Inscrit en
    Octobre 2007
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : heu...

    Informations forums :
    Inscription : Octobre 2007
    Messages : 648
    Par défaut
    Le constructeur de ta classe de base a deux paramètres x et y. Tu reprends ces paramètres dans la classe dérivée.
    Que se passerait-il s'il y en avait 100 ?
    Je pense pas beaucoup plus de choses que lorsque tu crées directement une instance de la classe que tu veux copier.

    Quoi qu'il en soit, j'ai essayé nos méthodes avec comme classe à copier lxml.etree.Element (si c'est bien celle à laquelle tu veux rajouter poids), ça marche pas

  13. #13
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    Quoi qu'il en soit, j'ai essayé nos méthodes avec comme classe à copier lxml.etree.Element (si c'est bien celle à laquelle tu veux rajouter poids), ça marche pas

    Ca marche !
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #une page en exemple
    html = parse('http://www.logic-immo.com/vente-010000000-87_1-PAS-DE-CALAIS_62000-0-a-0-0-a-0-0-a-0-0--0-0.htm').getroot()
    html=html.body # on ne garde par le header
    cleaner = Cleaner(style=True, links=True, add_nofollow=True, page_structure=False, safe_attrs_only=False)
     
    print html
    class pel(lxml.html.HtmlElement):
        def __init__(self,X,y):
            dico=X.__dict__
            dico["poids"]=y
            self.__dict__=dico
    phtml=pel(html,2)
    print phtml.poids
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  14. #14
    Membre émérite
    Homme Profil pro
    heu...
    Inscrit en
    Octobre 2007
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : heu...

    Informations forums :
    Inscription : Octobre 2007
    Messages : 648
    Par défaut
    C'est normal que ce que j'ai essayé hier ne marche pas... lxml.etree.Element est une fonction .

    Pourtant ta méthode n'est pas propre, et je trouve qu'elle ne marche pas vraiment d'ailleurs. Chez moi, le code suivant occasionne un crash pur et simple de python (pas une simple erreur...)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    >>> class Foo(lxml.html.HtmlElement):
    	def __init__(self,BodyElement,poids):
    		self.poids=poids
    		self.__dict__.update(BodyElement.__dict__)
     
     
    >>> b=Foo(a,56)
    >>> b.attrib
    Et le code suivant ne fonctionne pas des masses:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    >>> class Foo(lxml.html.HtmlElement):
    	def __init__(self,BodyElement,poids):
    		super(Foo,self).__init__()
    		self.poids=poids
    		self.__dict__.update(BodyElement.__dict__)
     
     
    >>> a=lxml.html.parse('http://www.google.fr/').getroot().body
    >>> a.__dict__
    {}
    >>> b=Foo(a,56)
    >>> a.attrib
    {'onload': "document.f.q.focus();if(document.images)new Image().src='/images/nav_logo4.png'", 'marginheight': '3', 'topmargin': '3', 'alink': '#ff0000', 'text': '#000000', 'bgcolor': '#ffffff', 'link': '#0000cc', 'vlink': '#551a8b'}
    >>> b.attrib
    {}
    Le truc, c'est que t'essayes de fusionner deux types différents... Alors que la solution est tellement simple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    >>> a=lxml.html.parse('http://www.google.fr/').getroot().body
    >>> a.poids=56
    >>> a.poids
    56
    #OU BIEN
    >>> a=lxml.html.parse('http://www.google.fr/').getroot().body
    >>> b=a.__copy__()
    >>> b.poids=108
    >>> b.poids
    108

  15. #15
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    Ma méthode fonctionne parfaitement chez moi, et je ne suis pas surpris que tes bouts ne code ne donnent rien de bon. Ce en quoi elle n'est pas propre je l'ai signalé dans un précédent post. Mais cela n'a (pour moi) pas d'importance, je préfère corrompre des objets pour réaliser une économie substantielle de mémoire.
    Cela dit ta dernière solution 'tellement simple' c'est ce que je ne veux à aucun prix.
    Python a beaucoup de qualités, plus de qualités que de défaut, et c'est un langage que j'apprécie, mais ce n'est pas à son honneur que de laisser écrire des choses pareilles.
    Car dans les objets 'Element' tu auras ceux qui auront un poids 'déclaré' et ceux qui n'en auront pas. Mais ce n'est pas tout. D'abord ce n'est pas seulement un poids que je veux rajouter, j'ai pris cet exemple pour faire simple. je veux en fait mapper les noeuds de l'arbre du document dans un espace sémantique à plusieurs dimensions pour faire des 'clusters'.
    Donc il y a des calculs longs et plus ou moins complexes sur ces paramètres. Ma question est avec ta solution 'simple' où et comment vais-je implémenter ces calculs (le plus souvent récursifs) ? Dans ma proposition c'est évident, ce seront des méthodes du nouvel objet dérivé. Mais ce n'est pas tout. Je peux être amené à supprimer ou a rajouter des membres à modifier les méthodes de calcul. En résumé je pars d'un arbre html brut, j'en fais une copie où tous les noeuds sont des noeuds 'augmentés' et après je fais ce que je veux au point de vue traitement en particulier je bénéficie de l'itérateur.
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  16. #16
    Membre émérite
    Homme Profil pro
    heu...
    Inscrit en
    Octobre 2007
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : heu...

    Informations forums :
    Inscription : Octobre 2007
    Messages : 648
    Par défaut
    hmmmm... Si j'avais su...

    Il est maintenant plus que clair pour moi que ce je t'ai proposé n'est pas du tout adapté... désolé .

    Du coup, je m'incline, me retire, et te souhaite bon courage pour la suite

  17. #17
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    Merci, c'est sympa d'avoir passé du temps à essayer de m'aider.
    A+ sur ce forum
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

Discussions similaires

  1. constructeur classe dérivée
    Par Nayila dans le forum Langage
    Réponses: 3
    Dernier message: 10/12/2007, 16h49
  2. cast d'objet parent en classe fille
    Par Plio dans le forum C++
    Réponses: 2
    Dernier message: 05/10/2007, 13h58
  3. Réponses: 8
    Dernier message: 17/04/2007, 11h35
  4. [c#]Constructeur de classe dérivée
    Par b4u dans le forum C#
    Réponses: 5
    Dernier message: 16/11/2006, 00h57
  5. creation d'objet de classe a partir de string
    Par mencaglia dans le forum C++
    Réponses: 1
    Dernier message: 14/03/2006, 09h56

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo