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.
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()
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.
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")
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.
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
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()
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)
Que dis-tu de ça :
def import_module(name):
mod = __import__(name)
for s in name.split('.')[1:]:
mod = getattr(mod, s)
return mod