233 votes

Instanciation dynamique à partir d'une chaîne de caractères du nom d'une classe dans un module importé dynamiquement ?

En Python, je dois instancier une certaine classe, en connaissant son nom dans une chaîne, mais cette classe "vit" dans un module importé dynamiquement. Voici un exemple :

chargeur-classe script :

import sys
class loader:
  def __init__(self, module_name, class_name): # both args are strings
    try:
      __import__(module_name)
      modul = sys.modules[module_name]
      instance = modul.class_name() # obviously this doesn't works, here is my main problem!
    except ImportError:
       # manage import error

le module script chargé dynamiquement :

class myName:
  # etc...

J'utilise cet arrangement pour que tout module chargé dynamiquement soit utilisé par la classe chargeur en suivant certains comportements prédéfinis dans les modules chargés dynamiquement...

324voto

Sven Marnach Points 133943

Vous pouvez utiliser getattr

getattr(module, class_name)

pour accéder à la classe. Code plus complet :

module = __import__(module_name)
class_ = getattr(module, class_name)
instance = class_()

Comme indiqué en dessous de nous pouvons utiliser importlib

import importlib
module = importlib.import_module(module_name)
class_ = getattr(module, class_name)
instance = class_()

3 votes

module = __import__(module, fromlist=[name]) n'a fonctionné que pour moi.

20 votes

Si quelqu'un a des problèmes avec la méthode d'importation mentionnée par Sven ci-dessus, j'ai trouvé que mon code fonctionnait mieux en utilisant la méthode suivante à la place importlib.import_module . Peut être utilisé comme : module = importlib.import_module(nom_du_module)

0 votes

@jpennell vous devriez poster cela comme réponse, il est souvent plus utile de pouvoir utiliser directement la chaîne retournée par obj.__module__

155voto

Régis B. Points 1188

Tl;dr

Importez le module Root avec importlib.import_module et charger la classe par son nom en utilisant getattr fonction :

# Standard import
import importlib
# Load "module.submodule.MyClass"
MyClass = getattr(importlib.import_module("module.submodule"), "MyClass")
# Instantiate the class (pass arguments to the constructor, if needed)
instance = MyClass()

explications

Vous ne voulez probablement pas utiliser __import__ pour importer dynamiquement un module par son nom, car il ne vous permet pas d'importer des sous-modules :

>>> mod = __import__("os.path")
>>> mod.join
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'join'

Ici c'est ce que dit la documentation python sur __import__ :

Note : Il s'agit d'une fonction avancée qui n'est pas nécessaire dans la programmation quotidienne de Python, contrairement à importlib.import_module(). programmation Python, contrairement à importlib.import_module().

Au lieu de cela, utilisez la méthode standard importlib pour importer dynamiquement un module par son nom. Avec getattr vous pouvez alors instancier une classe par son nom :

import importlib
my_module = importlib.import_module("module.submodule")
MyClass = getattr(my_module, "MyClass")
instance = MyClass()

Vous pourriez aussi écrire :

import importlib
module_name, class_name = "module.submodule.MyClass".rsplit(".", 1)
MyClass = getattr(importlib.import_module(module_name), class_name)
instance = MyClass()

Ce code est valable dans python 2.7 (y compris python 3).

1 votes

Peut-être que je ne comprends pas votre réponse, mais j'ai utilisé import pour importer des submodules : __import__("module." + submodule_name_string)

0 votes

Le code suivant donne lieu à une AttributeError : mod = __import__("os.path"); mod.join alors que les suivantes ne le font pas : mod = importlib.import_module("os.path"); mod.join

0 votes

Oh je vois, vous avez raison mais j'ai fait ce qui suit pour obtenir la méthode os.path.join : getattr(sys.modules["os.path"], "join")

15voto

AFoglia Points 3791

Utilice getattr pour obtenir un attribut à partir d'un nom dans une chaîne. En d'autres termes, obtenir l'instance en tant que

instance = getattr(modul, class_name)()

15voto

Andrejs Cainikovs Points 7758

Copier-coller de l'extrait :

import importlib
def str_to_class(module_name, class_name):
    """Return a class instance from a string reference"""
    try:
        module_ = importlib.import_module(module_name)
        try:
            class_ = getattr(module_, class_name)()
        except AttributeError:
            logging.error('Class does not exist')
    except ImportError:
        logging.error('Module does not exist')
    return class_ or None

10voto

Xema Points 549

On peut simplement utiliser le pydoc.locate fonction.

from pydoc import locate
my_class = locate("module.submodule.myclass")
instance = my_class()

0 votes

Devrait être une réponse acceptée

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