230 votes

Convertir une chaîne de caractères en objet de classe Python ?

Étant donné qu'une chaîne de caractères est entrée par l'utilisateur dans une fonction Python, j'aimerais en extraire un objet de classe s'il existe une classe portant ce nom dans l'espace de noms actuellement défini. Essentiellement, je veux l'implémentation d'une fonction qui produira ce genre de résultat :

class Foo:
    pass

str_to_class("Foo")
==> <class __main__.Foo at 0x69ba0>

Est-ce que c'est possible ?

183voto

sixthgear Points 3294

Ça pourrait marcher :

import sys

def str_to_class(classname):
    return getattr(sys.modules[__name__], classname)

141voto

S.Lott Points 207588

Avertissement : eval() peut être utilisé pour exécuter un code Python arbitraire. Vous devez nunca utiliser eval() avec des chaînes non fiables. (Voir Sécurité de la fonction eval() de Python sur les chaînes de caractères non fiables ? )

Cela semble le plus simple.

>>> class Foo(object):
...     pass
... 
>>> eval("Foo")
<class '__main__.Foo'>

138voto

Laurence Gonsalves Points 50783

Vous pourriez faire quelque chose comme :

globals()[class_name]

112voto

m.kocikowski Points 2414

Vous voulez que la classe Baz qui vit dans le module foo.bar . Avec Python 2.7, vous voulez utiliser importlib.import_module() car cela facilitera la transition vers Python 3 :

import importlib

def class_for_name(module_name, class_name):
    # load the module, will raise ImportError if module cannot be loaded
    m = importlib.import_module(module_name)
    # get the class, will raise AttributeError if class cannot be found
    c = getattr(m, class_name)
    return c

Avec Python < 2.7 :

def class_for_name(module_name, class_name):
    # load the module, will raise ImportError if module cannot be loaded
    m = __import__(module_name, globals(), locals(), class_name)
    # get the class, will raise AttributeError if class cannot be found
    c = getattr(m, class_name)
    return c

Utilisez :

loaded_class = class_for_name('foo.bar', 'Baz')

36voto

eugene Points 4556

J'ai regardé comment Django gère cela.

django.utils.module_loading a ceci

def import_string(dotted_path):
    """
    Import a dotted module path and return the attribute/class designated by the
    last name in the path. Raise ImportError if the import failed.
    """
    try:
        module_path, class_name = dotted_path.rsplit('.', 1)
    except ValueError:
        msg = "%s doesn't look like a module path" % dotted_path
        six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])

    module = import_module(module_path)

    try:
        return getattr(module, class_name)
    except AttributeError:
        msg = 'Module "%s" does not define a "%s" attribute/class' % (
            module_path, class_name)
        six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])

Vous pouvez l'utiliser comme import_string("module_path.to.all.the.way.to.your_class")

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