128 votes

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

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

Voici comment je m'y suis pris :

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 vraiment nécessaire.

Modification : j'utilise la version 2.6.5 de Python.

143voto

frm Points 1398

À partir de Python 2.7, vous pouvez utiliser la fonction importlib.import_module() fonction. 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()

3 votes

Il est à noter que la documentation de Python recommande l'utilisation de importlib.import_module() sur __import__() : docs.python.org/2/library/functions.html#__import__ -- pour 2.7+.

4 votes

import_module + rsplit \= La seule vraie voie.

38voto

Sven Marnach Points 133943

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'attribut fromlist argument :

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

Pour votre exemple abc.def.ghi.jkl.myfile.mymethod pour appeler cette fonction comme

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

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

Pour une tâche aussi simple, il n'y a pas d'avantage à utiliser l'outil d'évaluation de la qualité de l'eau. importlib module.

35voto

gecco Points 4063

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

__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é. Il suffit d'importer votre module comme ceci :

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

Mise à jour : Mise à jour de la version selon les commentaires ( Je dois admettre que je n'ai pas lu la chaîne à importer jusqu'à la fin et j'ai manqué le fait qu'une méthode d'un module doit être importée et non le 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")

18voto

Alaa Akiel Points 104
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, "classNameImportFromFile")

NClass = model() # Class From file

3 votes

Merci pour la réponse, juste un petit problème : je ne pense pas que .strip() se comporte correctement dans le cas que vous avez indiqué. Plus précisément, si le fichier commence par "py", ces caractères seront également supprimés. Par exemple, "pyfile.py".strip(".py") produit "file" où il serait préférable qu'il produise "pyfile" dans ce cas. name.replace(".py","") fonctionne très bien, cependant.

13voto

Charles Merriam Points 4498

Ce que vous essayez de faire à votre espace de noms local n'est pas clair. Je suppose que vous voulez juste my_method comme un 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()

Alors que vous ajoutez seulement my_method dans l'espace de nom local, vous chargez la chaîne de modules. Vous pouvez observer les changements en regardant les clés de sys.modules avant et après l'importation. J'espère que ceci est plus clair et plus précis que vos autres réponses.

Pour être complet, voici comment ajouter l'ensemble de la chaîne.

# 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()

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

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