2012-01-09 19 views
41

Ho una stringa, diciamo: abc.def.ghi.jkl.myfile.mymethod. Come faccio a importare dinamicamente mymethod?Importare dinamicamente un metodo in un file, da una stringa

Ecco come sono andato su di esso:

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('.')) 

Mi chiedo se i singoli moduli di importazione è richiesto a tutti.

Modifica: sto usando Python versione 2.6.5.

risposta

-2

Utilizzare importlib (solo 2,7+).

+1

io uso 2.6.5. Posso fare una cosa 'from __future__'? –

+5

No, '__future__' è per le funzionalità della lingua, non per i nuovi moduli stdlib. – ThiefMaster

+1

Usa il buit-in '__import__' come negli esempi sopra. Funziona a 2,5 e, senza parole chiave, prima di quello. –

17

Per pitone < 2.7 metodo built __ import__ può essere utilizzato:

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

Per Python> = 2.7 o 3.1 il metodo conveniente importlib.import_module è stato aggiunto. Basta importare il modulo come questo:

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

Aggiornamento: Versione aggiornata secondo i commenti (Devo ammettere che non ho letto la stringa da importare fino alla fine e ho perso il fatto che un metodo di un modulo deve essere importato e non un modulo stesso):

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") 
+6

Nessuna di queste soluzioni non funzionerà perché il primo parametro deve essere un * nome modulo * sia in "__import __()" che in "importlib.import_module()". –

+1

importlib.import_module ('abc.def.ghi.jkl.myfile.mymethod') non funzionerà perché devi specificare "quale modulo importare in termini assoluti o relativi" e non il nome "qualificato" del metodo. – frm

+0

Questo non funziona, ovviamente, poiché il primo parametro per __import__ dovrebbe essere un modulo, non una stringa. –

21

Non è necessario importare i singoli moduli. E 'sufficiente importare il modulo che si desidera importare un nome e di fornire l'argomento fromlist:

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

Per il vostro esempio abc.def.ghi.jkl.myfile.mymethod, chiamare questa funzione come

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

(Si noti che le funzioni a livello di modulo sono chiamate funzioni in Python, non metodi.)

Per un compito così semplice, non è vantaggioso utilizzare il modulo importlib.

+0

import_from() mi ha indirizzato nella giusta direzione. 'myClass = getattr (__ import __ (" module.to.import ", fromlist = [" myClassName "])," myClassName ")'. Grazie per l'aiuto! – Fydo

+1

L'approccio '__import__' funziona. Ma prova a eseguire 'help (__ import __)'. Dice "Poiché questa funzione è pensata per essere utilizzata dall'interprete Python e non per uso generale, è meglio usare" importlib.import_module() "per importare un modulo a livello di programmazione." – twasbrillig

+2

@twasbrillig: Quando ho risposto a questa domanda, Python 2.5 e 2.6 erano ancora ampiamente utilizzati. Oggi è sicuramente meglio usare 'importlib'. –

57

Da Python 2.7 è possibile utilizzare la funzione importlib.import_module(). È possibile importare un modulo e accedere a un oggetto definito all'interno di esso con il seguente codice:

from importlib import import_module 

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

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

met() 
+0

Vale la pena notare che i documenti Python consigliano di usare 'importlib.import_module()' su '__import __()': https://docs.python.org/2/library/functions.html#__import__ - per 2.7+. – BoltzmannBrain

+2

'import_module' ** + **' rsplit' ** = ** _The One True Way._ –

0

Il modo tendo a questo (così come un certo numero di altre librerie, come i piloni e incolla, se la mia memoria mi serve correttamente) è quello di separare il nome del modulo dal nome funzione/attributo utilizzando un ':' tra di loro. Vedere l'esempio seguente:

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

Questo rende la funzione import_from(path) di sotto di un po 'più facile da usare.

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() 
+1

Perché dovrei farlo? Ciò richiede al chiamante di unire il nome del modulo e il nome dell'attributo con due punti, e la funzione deve essere nuovamente divisa in due punti. Perché non usare semplicemente due parametri in primo luogo? –

+0

Spesso si verifica una situazione in cui si collegano i callback da un framework alla propria applicazione utilizzando i file di configurazione (.yaml, .ini, ecc.). Quindi, è possibile specificare la funzione che il framework deve chiamare, ecc., Con una singola stringa nel file di configurazione. –

+0

Beh, si, si potrebbe desiderare di scegliere questo come sintassi del file di configurazione. Ma come si collega alla domanda dell'OP? (E anche se avessi scelto questa come sintassi del mio file di configurazione, preferirei che fosse analizzata dal mio parser di file di configurazione, non dalle funzioni API casuali.) –

3

Non è chiaro cosa si sta tentando di fare nel proprio spazio dei nomi locale. Immagino tu voglia solo il my_method come locale, digitando 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() 

Mentre si aggiunge solo my_method al namespace locale, tu caricare la catena di moduli. Puoi guardare le modifiche guardando i tasti di sys.modules prima e dopo l'importazione. Spero che questo sia più chiaro e più accurato delle altre risposte.

Per completezza, è così che si aggiunge l'intera catena.

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

E, infine, se si utilizza __import__() e avete modificato si cerca percorso dopo il programma è stato avviato, potrebbe essere necessario utilizzare __import__(normal args, globals=globals(), locals=locals()). Il perché è una discussione complessa.

+0

Il tuo primo esempio di 'the_module' e' same_module' è sbagliato e produrre risultati diversi. Downvoting. – sleepycal

0

Questo sito ha una bella soluzione: load_class. Io lo uso come questo:

foo = load_class(package.subpackage.FooClass)() 
type(foo) # returns FooClass 
1
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 
Problemi correlati