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 :

Instancier une classe dont le nom est contenu dans une String


Sujet :

Python

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 15
    Points : 11
    Points
    11
    Par défaut Instancier une classe dont le nom est contenu dans une String
    Bonjour,


    Je veux instancier une classe dont je ne connais pas le nom à l'avance. Il sera dans une String lors de l'execution du programme.

    Idéalement, je voudrais avoir un fichier de config qui contient des noms de classes, par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    [maSection]
    actions = monPackage.Classe1
    action2 = Classe2
    Et dans mon code, je voudrais pouvoir instancier ma classe selon ce paramètre. Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    action = ConfigReader.get(maSection, actions)
    monInstance = [fonction/action/astuce](action)(paramInstance)
    Je sais qu'il est possible d'instancier un module dynamiquement avec __import__, par exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    monModule = __import__(actions)
    Mais je n'ai pas réussi à instancier la classe sans faire de test sur son nom.

    Une idée ?

    Stéphane

  2. #2
    Expert éminent sénior
    Avatar de Guigui_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2002
    Messages
    1 864
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2002
    Messages : 1 864
    Points : 10 067
    Points
    10 067

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 15
    Points : 11
    Points
    11
    Par défaut
    Merci mais malheureusement cela ne fournit pas la réponse à mon problème !
    Je ne veux pas déclarer un nouvel attribut ou une nouvelle fonction, mais instancier une nouvelle classe ...

    Quelque chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    maClasse = "ActionsPackage.ClasseAction1"
    monInstance = __import__(maClasse).__init__()
    Malheureusement ce code ne marche pas car __import__ ne permet d'importer que des modules et non des classes.

    Merci quand même.

  4. #4
    Membre émérite
    Avatar de DelphiManiac
    Homme Profil pro
    Homme à tout faire
    Inscrit en
    Mars 2002
    Messages
    1 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Homme à tout faire
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 147
    Points : 2 533
    Points
    2 533
    Par défaut
    Admettons que j'ai une arborescence du style suivant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Dossier : mypackage
        File : __init__.py
        File : module.py
    File  : test.py
    avec __init__.py vide et module.py contenant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    class Test():
        def my_print(self, str):
            print str
    Le fichier test.py est le suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    my_package = 'mypackage'
    my_module = 'module'
    my_class = 'Test'
     
    package = __import__ (my_package, fromlist=[my_module])
    cls = package.__dict__[my_module].__dict__[my_class]()
     
    cls.my_print ("coucou")
    Est ce que ça réponds à la question ?
    Si ce message vous a semblé utile, il est possible qu'il soit utile à d'autres personnes. Pensez au . Et n'oubliez pas le le moment venu !

    On n'a pas à choisir si l'on est pour ou contre la décroissance, elle est inéluctable, elle arrivera qu'on le veuille ou non.

  5. #5
    Membre averti
    Homme Profil pro
    Responsable du parc et des réseaux de télécommunication
    Inscrit en
    Mai 2003
    Messages
    290
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Responsable du parc et des réseaux de télécommunication
    Secteur : Industrie

    Informations forums :
    Inscription : Mai 2003
    Messages : 290
    Points : 388
    Points
    388
    Par défaut
    Bonjour,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    [maSection]
    action1 = Classe1
    action2 = Classe2
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    import monModule
    action = ConfigReader.get('maSection', 'action1')
    monInstance = getattr(monModule,action)
    monInstance()

  6. #6
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2003
    Messages
    302
    Détails du profil
    Informations personnelles :
    Localisation : Algérie

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Distribution

    Informations forums :
    Inscription : Janvier 2003
    Messages : 302
    Points : 316
    Points
    316
    Par défaut
    Salut,

    Je préfère la solution de pierjean qui me parait la plus propre.

  7. #7
    Membre émérite
    Avatar de DelphiManiac
    Homme Profil pro
    Homme à tout faire
    Inscrit en
    Mars 2002
    Messages
    1 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Homme à tout faire
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 147
    Points : 2 533
    Points
    2 533
    Par défaut
    Citation Envoyé par yacinechaouche Voir le message
    Salut,

    Je préfère la solution de pierjean qui me parait la plus propre.
    Le but de la réponse n'étais pas de faire la solution la plus propre mais de montrer jusqu'ou on pouvait aller, encore que j'aurais pu passer aussi en string le nom de la méthode à appeler.
    Si ce message vous a semblé utile, il est possible qu'il soit utile à d'autres personnes. Pensez au . Et n'oubliez pas le le moment venu !

    On n'a pas à choisir si l'on est pour ou contre la décroissance, elle est inéluctable, elle arrivera qu'on le veuille ou non.

  8. #8
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2003
    Messages
    302
    Détails du profil
    Informations personnelles :
    Localisation : Algérie

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Distribution

    Informations forums :
    Inscription : Janvier 2003
    Messages : 302
    Points : 316
    Points
    316
    Par défaut
    Salut,

    DelphiManiac, tu utilises des attributs qui sont sensés être cachés de l'utilisateur (__dict__). Des fonctions telles que getattr et hasattr utilisent pour nous ces attributs cachés pour que l'inspection des objets soit tâche facile pour nous. Alors, autant les utiliser

  9. #9
    Membre émérite
    Avatar de DelphiManiac
    Homme Profil pro
    Homme à tout faire
    Inscrit en
    Mars 2002
    Messages
    1 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Homme à tout faire
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 147
    Points : 2 533
    Points
    2 533
    Par défaut
    Il est vrai que dans ce contexte utilisé getattr est surement plus approprié.

    Concernant les identifiants préfixé de 2 '_', ce sont des éléments pseudo privés. Par ailleurs, il est des fois nécessaire de les utiliser comme dans __import__ pour faire un import dynamique.

    L'usage de __dict__ est plus souvent réservé à l'introspection vu que l'on est pas censé connaitre les éléments que l'on recherche.

    Personnellement et dans le contexte de la question, je préfère utiliser __dict__ qui me parait plus "lisible" que la syntaxe équivalente avec getattr : cls = getattr(getattr(package, my_module), my_class)()

    Mais c'est un choix bien personnel
    Si ce message vous a semblé utile, il est possible qu'il soit utile à d'autres personnes. Pensez au . Et n'oubliez pas le le moment venu !

    On n'a pas à choisir si l'on est pour ou contre la décroissance, elle est inéluctable, elle arrivera qu'on le veuille ou non.

  10. #10
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    119
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 119
    Points : 139
    Points
    139
    Par défaut
    En fait, __dict__ tient du détail d'implementation, il y a quelques différences entre faire a.__dict__[x] et getattr(a,x):
    • __dict__ n'existe pas pour les classes qui ont des __slots__
    • __dict__ ne retourne pas les méthodes et d'une manière générale ce qui dépend de la classe, par exemple les attributs de classes
    • getattr peut appeler __getattr__ et __getattribute__


    Par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    >>> class g:              
    ...     toto=1
    ...
    >>> g.toto,g().toto,getattr(g(),'toto')
    (1, 1, 1)               
    >>> g().__dict__          
    {}

  11. #11
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2003
    Messages
    302
    Détails du profil
    Informations personnelles :
    Localisation : Algérie

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Distribution

    Informations forums :
    Inscription : Janvier 2003
    Messages : 302
    Points : 316
    Points
    316
    Par défaut
    Citation Envoyé par Fructidor Voir le message
    • __dict__ n'existe pas pour les classes qui ont des __slots__
    • __dict__ ne retourne pas les méthodes et d'une manière générale ce qui dépend de la classe, par exemple les attributs de classes
    • getattr peut appeler __getattr__ et __getattribute__

    Pour éviter les confusions :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class spam:
        __slots__ = ["egg"]
        egg = 1
        def ham(self):
            print egg
        def __init__(self):
            self.jam = 0
     
    print spam.__dict__
    print spam().__dict__
    imprime
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    '__module__': '__main__', 'ham': <function ham at 0xb7dc548c>, '__slots__': ['egg'], 'egg': 1, '__doc__': None, '__init__': <function __init__ at 0xb7dc541c>}
    {'jam': 0}
    Donc :
    • __dict__ contient ce qui est dans la classe, si on l'appelle sur la classe
    • __dict__ contient les méthodes de la classe, si on l'appelle sur la classe
    • On peut accéder au dictionnaire de la classe à partir de son instance en faisant

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    print spam().__class__.__dict__
    Pour ce qui concerne les __slots__, que je ne connais pas très bien, il s'avère que le code que j'ai essayé a bien affiché le dictionnaire de l'instance, même si la classe contient bien un __slots__. Peux-tu nous en dire plus sur ce point ?


    Merci.

  12. #12
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970

  13. #13
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 15
    Points : 11
    Points
    11
    Par défaut
    Merci pour ces réponses, c'est tout simplement magnifique :-)

    J'ai utilisé un peu des deux réponses, car j'ai mis dans mon fichier de config
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    [section]
    action = Production.Extractors.OracleExtractor
    où OracleExtractor est la classe à instancier

    Mon arborescence est la suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Dossier : Production/Extraction
        File : __init__.py
        File : Oracle.py
    File  : test.py
    - Oracle.py contient la classe OracleExtractor()
    - __init__.py qui contient
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    from Oracle import OracleExtractor
    ce qui me permet d'instancier ma classe de façon jolie comme from Production.Extractors import OracleExtractor




    Ca marche en faisant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    package = "Production.Extractors"
    module = "Extractors"
    maclass = "OracleExtractor"
     
    module = __import__(package, fromlist=[module])
    maclass = module.getattr(maclass )
     
    extractor = maclass ()
    extractor.launch()
    ...
    J'ai écris une petite procédure (y'a sûrement mieux mais au moins ça fait le taf pour moi)
    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
     
    maclass = getClassFromString("Production.Extractors.OracleExtractor")
    extractor = maclass ()
    extractor.launch()
    ...
     
    def getClassFromString(absoluteClass):
        l = absoluteClass.split('.')
     
        packageName = ""
        for i in range(len(l)-1):
            packageName = packageName + l[i] + "."
     
        packageName = packageName[:-1]
        moduleName  = l[i]
        className  = l[i+1]
     
        module = __import__(packageName, fromlist=[moduleName])
     
        return getattr(module, className)


    Je suis donc assez content, puisque ça marche.
    Mais néanmoins j'ai l'impression de passer à côté de quelque chose à propos des __init__.py des différents modules/packages puisque j'aurais plutôt vu :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    module = __import__("Production.Extractors")
    maclass = getattr(module, "OracleExtractor")
    Mais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    print module
    <module 'Production' from 'D:\eclipse workspace\APPLICATION\bin\Production\__init__.pyc'>

    En espérant n'avoir pas été trop long ni confut.

    En tout cas merci pour vos réponses !!
    Stéphane

  14. #14
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    C'est pour ça que j'ai donné le lien dans mon précédent message, tout y est expliqué.

  15. #15
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    119
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 119
    Points : 139
    Points
    139
    Par défaut
    Bonjour,

    je reviens rapidement sur le post de yacinechaouche:

    Citation Envoyé par yacinechaouche Voir le message
    Pour éviter les confusions :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class spam:
        __slots__ = ["egg"]
        egg = 1
        def ham(self):
            print egg
        def __init__(self):
            self.jam = 0
     
    print spam.__dict__
    print spam().__dict__
    pour que __slots__ fonctionne, il faut que la classe dérive d'object ("new-style class"). Je ne l'utilise pas couramment (en fait, jamais). L'idée est d'optimiser les resources en évitant le passage par une map, notamment en cas de création de nombreuses instances. Avec cette modification, on a:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    class spam(object):
    ...
    >>> spam()
    AttributeError: 'spam' object has no attribute 'jam'
    l'initialisation a raté car la création de l'attribut jam a échoué (il ne fait pas partie de la liste __slots__)
    • __dict__ contient ce qui est dans la classe, si on l'appelle sur la classe
    • __dict__ contient les méthodes de la classe, si on l'appelle sur la classe
    oui, mais uniquement les méthodes et attributs de la classe elle-même, et notamment pas les méthodes héritées:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    >>> class a:
    ...     def toto(self):pass
    ...
    >>> class b(a):
    ...     def titi(self):pass
    ...
    >>> getattr(b,'toto')
    <unbound method b.toto>
    >>> b.__dict__['toto']
    KeyError: 'toto'
    • On peut accéder au dictionnaire de la classe à partir de son instance en faisant

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    print spam().__class__.__dict__
    A nouveau, on va avoir le problème de l'héritage. Donc si on veut seulement les attribut de la classe, sans les super classes, OK. Si on veut tous les attributs auxquels l'instance et la classe vont avoir accès, il faut utiliser dir() qui en sous-main va inspecter tous les __dicts__ et les __slots__.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    >>> b.__dict__
    {'__module__': '__main__', 'titi': <function titi at 0x00AE9330>, '__doc__': Non
    e}
    >>> dir(b)
    ['__doc__', '__module__', 'titi', 'toto']
    Mon point de vue, c'est bien sûr qu'on peut utiliser __dict__, et dans de nombreux cas cela aura les résultats que tu présentes, mais qu'il faut garder à l'esprit qu'il ne va remonter que les attributs "propres" de l'instance ou de la classe.
    getattr et dir, d'un autre coté, sont des protocoles qui permettent d'accéder aux attributs et méthodes en faisant abstraction de l'implémentation de la classe, du fait qu'elle soit dérivée ou new-style, etc.

  16. #16
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2003
    Messages
    302
    Détails du profil
    Informations personnelles :
    Localisation : Algérie

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Distribution

    Informations forums :
    Inscription : Janvier 2003
    Messages : 302
    Points : 316
    Points
    316
    Par défaut
    Merci pour cette explication très détaillée et instructive ! notamment pour les slots que je n'ai jamais utilisé moi non plus. Je ne vois pas encore l'intérêt d'interdire l'ajout d'attributs supplémentaires à une instance de classe. Ce qui m'avait séduit très tôt chez python c'est que, tout comme chez smalltalk, on peut bidouiller un objet même après sa création, lui ajouter des attributs ou les changer etc. Allez faire ça en Java ou en C++...

    Effectivement __dict__ ne contient que ce qui est dans le namespace de l'objet qu'on inspecte, qu'il soit instance, classe, type ou autre. getattr et dir sont donc plus puissants puisqu'ils vont chercher les attributs hérités.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. MACRO de copie d'une feuille dont le nom est contenu dans une cellule
    Par youssy dans le forum Macros et VBA Excel
    Réponses: 0
    Dernier message: 01/03/2015, 19h39
  2. [XL-2007] Sélectionner une feuille dont le nom est contenu dans une cellule
    Par Nonno 94 dans le forum Macros et VBA Excel
    Réponses: 4
    Dernier message: 30/06/2014, 20h47
  3. Réponses: 3
    Dernier message: 07/01/2010, 16h54
  4. Réponses: 7
    Dernier message: 25/10/2005, 15h19
  5. [Reflection] Executer une fonction dont le nom est contenu dans un String
    Par christobal dans le forum API standards et tierces
    Réponses: 8
    Dernier message: 05/07/2004, 15h23

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