56 votes

Comment créer dynamiquement une instance d'une classe en python ?

Je dispose d'une liste de noms de classes et je souhaite créer leurs instances de manière dynamique, par exemple :

names=[
'foo.baa.a',
'foo.daa.c',
'foo.AA',
 ....
]

def save(cName, argument):
 aa = create_instance(cName) # how to do it?
 aa.save(argument)

save(random_from(names), arg)

Comment créer dynamiquement ces instances en Python ? Merci !

78voto

elewinso Points 307

En supposant que vous ayez déjà importé les classes concernées en utilisant quelque chose comme

from [app].models import *

Tout ce que vous avez à faire, c'est

klass = globals()["class_name"]
instance = klass()

2 votes

Belle réponse.

1 votes

Pourquoi l'avez-vous appelé klass ? Ce mot a-t-il une signification particulière ?

0 votes

Fonctionne avec les modèles django

27voto

Scott Lance Points 1581

On parle souvent de réflexion ou parfois d'introspection. Consultez des questions similaires dont la réponse correspond à ce que vous essayez de faire :

Python a-t-il un équivalent à la classe Java forname ?

Peut-on utiliser une chaîne de caractères pour instancier une classe en Python ?

1 votes

Certains de ces exemples utilisent __import__ Pour les codes plus récents, vous pouvez passer à importlib docs.python.org/dev/library/importlib.html . (py>=2.7 | >=3.1)

13 votes

N'utilisez pas de liens, mais fournissez une véritable description.

9voto

Tobias Ernst Points 713

Cela a fonctionné pour moi :

from importlib import import_module

class_str: str = 'A.B.YourClass'
try:
    module_path, class_name = class_str.rsplit('.', 1)
    module = import_module(module_path)
    return getattr(module, class_name)
except (ImportError, AttributeError) as e:
    raise ImportError(class_str)

2 votes

Cela fonctionne très bien pour moi ! Merci !

2 votes

Oui, utiliser importlib pour résoudre la classe est bien mieux que de le faire manuellement avec des anti-patterns comme star-imports. Cette réponse est, depuis Python 3.3, la meilleure solution.

8voto

S.Lott Points 207588

Il est souvent possible d'éviter complètement le traitement des chaînes de caractères.

import foo.baa 
import foo.AA
import foo

classes = [ foo.baa.a, foo.daa.c, foo.AA ]

def save(theClass, argument):
   aa = theClass()
   aa.save(argument)

save(random.choice(classes), arg)

Notez que nous n'utilisons pas de représentation sous forme de chaîne de caractères du nom de la classe.

En Python, vous pouvez simplement utiliser la classe elle-même.

0 votes

Supposons que le tableau provienne de la base de données. Cette solution n'est donc pas utile.

0 votes

Et bien c'est ce qu'il faut faire type(cName)(**arguments)

6voto

hb2pencil Points 704

Vous pouvez utiliser la fonction intégrée de python eval() pour instancier vos classes. Comme ceci :

aa = eval(cName)()

Avis !

L'utilisation d'eval est dangereuse et constitue la clé de nombreux risques de sécurité basés sur des injections de code.

7 votes

N'utilisez pas eval car il est susceptible de poser des problèmes de sécurité.

2 votes

Et comment est-elle sensible ?

0 votes

En fonction du contexte, si cName provient d'une entrée d'un utilisateur, c'est un danger car un hacker peut y injecter du code Python : c'est vrai, mais bien souvent vous n'en avez besoin que pour configurer votre application à partir d'un fichier texte ou d'une variable d'environnement qui n'est contrôlée que par les développeurs/administrateurs, dans ce cas c'est suffisamment sûr et simple.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X