web-dev-qa-db-fra.com

Importer dynamiquement une méthode dans un fichier, à partir d'une chaîne

J'ai une chaîne, disons: abc.def.ghi.jkl.myfile.mymethod. Comment importer dynamiquement mymethod?

Voici comment je suis allé à ce sujet:

def get_method_from_file(full_path):
    if len(full_path) == 1:
        return map(__import__,[full_path[0]])[0]
    return getattr(get_method_from_file(full_path[:-1]),full_path[-1])


if __name__=='__main__':
    print get_method_from_file('abc.def.ghi.jkl.myfile.mymethod'.split('.'))

Je me demande si l'importation de modules individuels est nécessaire.

Edit: J'utilise Python version 2.6.5.

56
Lakshman Prasad

Depuis Python 2.7, vous pouvez utiliser la fonction importlib.import_module () . Vous pouvez importer un module et accéder à un objet défini dans celui-ci avec le code suivant:

from importlib import import_module

p, m = name.rsplit('.', 1)

mod = import_module(p)
met = getattr(mod, m)

met()
78
frm

Vous n'avez pas besoin d'importer les modules individuels. Il suffit d'importer le module à partir duquel vous souhaitez importer un nom et de fournir l'argument fromlist:

def import_from(module, name):
    module = __import__(module, fromlist=[name])
    return getattr(module, name)

Pour votre exemple abc.def.ghi.jkl.myfile.mymethod, appelez cette fonction en tant que

import_from("abc.def.ghi.jkl.myfile", "mymethod")

(Notez que les fonctions de niveau module sont appelées fonctions en Python, pas des méthodes.)

Pour une tâche aussi simple, l'utilisation du module importlib ne présente aucun avantage.

25
Sven Marnach

Pour Python <2.7, la méthode intégrée _ IMPORT_ peut être utilisée:

__import__('abc.def.ghi.jkl.myfile.mymethod', fromlist=[''])

Pour Python> = 2.7 ou 3.1, la méthode pratique importlib.import_module a été ajoutée. Importez votre module comme ceci:

importlib.import_module('abc.def.ghi.jkl.myfile.mymethod')

Update: Version mise à jour en fonction des commentaires (je dois avouer que je n'ai pas lu la chaîne à importer jusqu'à la fin et que j'ai raté le fait qu'une méthode d'un module doit être importée et pas un module lui-même ):

Python <2.7:

mymethod = getattr(__import__("abc.def.ghi.jkl.myfile", fromlist=["mymethod"]))

Python> = 2.7:

mymethod = getattr(importlib.import_module("abc.def.ghi.jkl.myfile"), "mymethod")
18
gecco

Ce que vous essayez de faire pour votre espace de noms local n'est pas clair. Je suppose que vous voulez juste my_method en tant que local, en tapant output = my_method()

# This is equivalent to "from a.b.myfile import my_method"
the_module = importlib.import_module("a.b.myfile")
same_module = __import__("a.b.myfile")
# import_module() and __input__() only return modules
my_method = getattr(the_module, "my_method")

# or, more concisely,
my_method = getattr(__import__("a.b.myfile"), "my_method")
output = my_method()

Bien que vous ajoutiez uniquement my_method à l'espace de noms local, vous chargez la chaîne de modules. Vous pouvez regarder les changements en regardant les touches de sys.modules avant et après l'importation. J'espère que cela est plus clair et plus précis que vos autres réponses.

Pour être complet, voici comment vous ajoutez la chaîne entière.

# This is equivalent to "import a.b.myfile"
a = __import__("a.b.myfile")
also_a = importlib.import_module("a.b.myfile")
output = a.b.myfile.my_method()

# This is equivalent to "from a.b import myfile"
myfile = __import__("a.b.myfile", fromlist="a.b")
also_myfile = importlib.import_module("a.b.myfile", "a.b")
output = myfile.my_method()

Enfin, si vous utilisez __import__() et avez modifié votre chemin de recherche après le démarrage du programme, vous devrez peut-être utiliser __import__(normal args, globals=globals(), locals=locals()). Le pourquoi est une discussion complexe.

5
Charles Merriam
from importlib import import_module


name = "file.py".strip('.py')
# if Path like : "path/python/file.py" 
# use name.replaces("/",".")

imp = import_module(name)

# get Class From File.py
model = getattr(imp, "naemClassImportFromFile")

NClass = model() # Class From file 
2
Alaa Akiel

La façon dont j'ai tendance à le faire (ainsi que plusieurs autres bibliothèques, telles que pylônes et coller, si ma mémoire est correcte) consiste à séparer le nom du module du nom de la fonction/attribut en utilisant un ':' entre eux. . Voir l'exemple suivant:

'abc.def.ghi.jkl.myfile:mymethod'

Cela rend la fonction import_from(path) ci-dessous un peu plus facile à utiliser.

def import_from(path):
    """
    Import an attribute, function or class from a module.
    :attr path: A path descriptor in the form of 'pkg.module.submodule:attribute'
    :type path: str
    """
    path_parts = path.split(':')
    if len(path_parts) < 2:
        raise ImportError("path must be in the form of pkg.module.submodule:attribute")
    module = __import__(path_parts[0], fromlist=path_parts[1])
    return getattr(module, path_parts[1])


if __name__=='__main__':
    func = import_from('a.b.c.d.myfile:mymethod')
    func()
0
Kris Hardy

Ce site a une solution intéressante: load_class . Je l'utilise comme ça:

foo = load_class(package.subpackage.FooClass)()
type(foo) # returns FooClass

Comme demandé, voici le code du lien Web:

import importlib

def load_class(full_class_string):
    """
    dynamically load a class from a string
    """

    class_data = full_class_string.split(".")
    module_path = ".".join(class_data[:-1])
    class_str = class_data[-1]

    module = importlib.import_module(module_path)
    # Finally, we retrieve the Class
    return getattr(module, class_str)
0
kingaj

Que dis-tu de ça :

def import_module(name):

    mod = __import__(name)
    for s in name.split('.')[1:]:
        mod = getattr(mod, s)
    return mod
0
Aymen Alsaadi