कैसे एक मॉड्यूल आयात करने के लिए स्ट्रिंग के रूप में अपना नाम दिया?


543

मैं एक पायथन एप्लिकेशन लिख रहा हूं जो एक तर्क के रूप में एक कमांड के रूप में लेता है, उदाहरण के लिए:

$ python myapp.py command1

मैं चाहता हूं कि एप्लिकेशन को एक्स्टेंसिबल होना चाहिए, यानी मुख्य एप्लिकेशन स्रोत को बदलने के बिना नए आदेशों को लागू करने वाले नए मॉड्यूल को जोड़ने में सक्षम होना चाहिए। पेड़ कुछ इस तरह दिखता है:

myapp/
    __init__.py
    commands/
        __init__.py
        command1.py
        command2.py
    foo.py
    bar.py

इसलिए मैं चाहता हूं कि एप्लिकेशन रनटाइम पर उपलब्ध कमांड मॉड्यूल को ढूंढे और उपयुक्त को निष्पादित करे।

पायथन एक __import__ फ़ंक्शन को परिभाषित करता है , जो एक मॉड्यूल नाम के लिए एक स्ट्रिंग लेता है:

__import __ (नाम, ग्लोबल्स = कोई नहीं, स्थानीय = कोई नहीं, सूची = (), स्तर = ०)

फ़ंक्शन मॉड्यूल नाम का आयात करता है, संभवतः दिए गए ग्लोबल्स और स्थानीय लोगों का उपयोग करके यह निर्धारित करने के लिए कि पैकेज संदर्भ में नाम की व्याख्या कैसे करें। Fromlist ऑब्जेक्ट या सबमॉड्यूल का नाम देता है जिसे नाम द्वारा दिए गए मॉड्यूल से आयात किया जाना चाहिए।

स्रोत: https://docs.python.org/3/library/functions.html# आयात

इसलिए वर्तमान में मेरे पास कुछ ऐसा है:

command = sys.argv[1]
try:
    command_module = __import__("myapp.commands.%s" % command, fromlist=["myapp.commands"])
except ImportError:
    # Display error message

command_module.run()

यह ठीक काम करता है, मैं बस सोच रहा हूं कि क्या इस कोड के साथ हम क्या कर रहे हैं, इसे पूरा करने के लिए संभवतः एक और अधिक मुहावरेदार तरीका है।

ध्यान दें कि मैं विशेष रूप से अंडे या विस्तार बिंदुओं का उपयोग करना नहीं चाहता हूं। यह एक ओपन-सोर्स प्रोजेक्ट नहीं है और मुझे "प्लगइन्स" होने की उम्मीद नहीं है। मुद्दा यह है कि मुख्य एप्लिकेशन कोड को सरल बनाया जाए और हर बार एक नया कमांड मॉड्यूल जोड़े जाने पर इसे संशोधित करने की आवश्यकता को हटाया जाए।


क्या करता है = = "" myapp.commands "]
पीटर म्यूलर

@ PieterMüller: एक अजगर शेल प्रकार में यह dir(__import__):। इस सूची को "नाम आयात से ..." का अनुकरण करने के लिए नामों की एक सूची होनी चाहिए।
मविमावि


2019 तक, आपको इसके लिए दिखना चाहिए importlib: stackoverflow.com/a/54956419/687896
ब्रांट

__Import__ का उपयोग न करें पायथन डॉक एक importlib.import_module
fcm

जवाबों:


321

पायथन 2.7 / 3.1 से अधिक उम्र के साथ, यह बहुत ज्यादा है कि आप इसे कैसे करते हैं।

नए संस्करण के लिए, देखें importlib.import_moduleके लिए अजगर 2 और और अजगर 3

आप चाहें execतो उपयोग कर सकते हैं ।

या इसका उपयोग करके __import__आप मॉड्यूल की सूची आयात कर सकते हैं:

>>> moduleNames = ['sys', 'os', 're', 'unittest'] 
>>> moduleNames
['sys', 'os', 're', 'unittest']
>>> modules = map(__import__, moduleNames)

पायथॉन में सीधे गोता लगाने से बचा


7
निष्पादन के लिए अंतर क्या है?
user1767754

1
आप __init__उस मॉड्यूल का उपयोग कैसे कर सकते हैं ?
डोरियन डोर

7
ओपी के लिए इस समाधान के साथ एक समस्या यह है कि एक या दो खराब "कमांड" मॉड्यूल के लिए अपवादों को फंसाने से उसका पूरा कमांड-ऐप एक अपवाद पर विफल हो जाता है। व्यक्तिगत रूप से मैं एक कोशिश में लिपटे प्रत्येक आयात पर लूप के लिए चाहूंगा : mods = __ import __ () \ nexcept ImportError त्रुटि के रूप में: रिपोर्ट (त्रुटि) अन्य आदेशों को काम जारी रखने की अनुमति देने के लिए जबकि बुरे लोग ठीक हो जाते हैं।
DevPlayer

7
इस समाधान के साथ एक और समस्या, जैसा कि नीचे डेनिस मालिनोव्स्की बताते हैं, कि अजगर डॉक्स खुद को इस्तेमाल न करने की सलाह देते हैं __import__। 2.7 डॉक्स: "क्योंकि यह फ़ंक्शन Python दुभाषिया द्वारा उपयोग के लिए है और सामान्य उपयोग के लिए नहीं है ताकि importlib.import_module () ... का उपयोग करना बेहतर हो।" python3 का उपयोग करते समय, impमॉड्यूल इस समस्या को हल करता है, जैसा कि नीचे monkut उल्लेख है।
LiavK

2
@JohnWu की जरूरत क्यों है foreachजब आपके पास है for element inऔर map()यद्यपि :)
काऊबर्ट

300

पायथन 2.7 और 3.1 के लिए अनुशंसित तरीका और बाद में importlibमॉड्यूल का उपयोग करना है:

importlib.import_module (नाम, पैकेज = कोई नहीं)

एक मॉड्यूल आयात करें। नाम तर्क निर्दिष्ट करता है कि पूर्ण या सापेक्ष शब्दों में आयात करने के लिए कौन सा मॉड्यूल (जैसे या तो pkg.mod या ..मॉड)। यदि नाम सापेक्ष रूप में निर्दिष्ट किया गया है, तो पैकेज तर्क को उस पैकेज के नाम पर सेट किया जाना चाहिए जो पैकेज नाम (उदाहरण के लिए import_module ('.. mod', 'pkg.subpkgkg) को हल करने के लिए एंकर के रूप में कार्य करना है। pkg.mod आयात करेगा)।

जैसे

my_module = importlib.import_module('os.path')

2
किस स्रोत या प्राधिकरण द्वारा अनुशंसित?
मच्युलेनिक

66
उपर्युक्त मॉड्यूल के पक्ष में फ़ंक्शन का उपयोग करने के खिलाफ दस्तावेज़ीकरण सलाह देता है __import__
डेनिस मालिनोव्स्की

8
यह आयात के लिए अच्छी तरह से काम करता है os.path; कैसे के बारे में from os.path import *?
नाम जी वीयू

5
मुझे यहाँ उत्तर मिलता है stackoverflow.com/a/44492879/248616 यानी। कॉलिंगglobals().update(my_module.__dict)
Nam G VU

2
@NamGVU, यह एक खतरनाक तरीका है क्योंकि यह आपके ग्लोबल्स को प्रदूषित कर रहा है और समान नामों वाले किसी भी पहचानकर्ता को ओवरराइड कर सकता है। आपके द्वारा पोस्ट किया गया लिंक इस कोड का एक बेहतर, बेहतर संस्करण है।
डेनिस मालिनोव्स्की

132

नोट: आयात के पक्ष में पायथन 3.4 के बाद छोटा सा भूत को हटा दिया गया है

जैसा कि उल्लेख किया गया है कि छोटा सा भूत आपको लोडिंग कार्य प्रदान करता है:

imp.load_source(name, path)
imp.load_compiled(name, path)

मैं इन का उपयोग किया है इससे पहले कि कुछ इसी तरह प्रदर्शन करने के लिए।

मेरे मामले में मैंने एक विशिष्ट वर्ग को परिभाषित तरीकों के साथ परिभाषित किया जो आवश्यक थे। एक बार जब मैंने मॉड्यूल लोड किया तो मैं जांच करूंगा कि क्या वर्ग मॉड्यूल में था, और फिर उस वर्ग का एक उदाहरण बनाएं, कुछ इस तरह से:

import imp
import os

def load_from_file(filepath):
    class_inst = None
    expected_class = 'MyClass'

    mod_name,file_ext = os.path.splitext(os.path.split(filepath)[-1])

    if file_ext.lower() == '.py':
        py_mod = imp.load_source(mod_name, filepath)

    elif file_ext.lower() == '.pyc':
        py_mod = imp.load_compiled(mod_name, filepath)

    if hasattr(py_mod, expected_class):
        class_inst = getattr(py_mod, expected_class)()

    return class_inst

2
अच्छा और सरल उपाय। मैंने एक समान लिखा है: stamat.wordpress.com/dynamic-module-import-in-python लेकिन आपके कुछ दोष हैं: अपवादों के बारे में क्या? IOError और ImportError? संकलित संस्करण के लिए पहले और फिर स्रोत संस्करण के लिए जाँच क्यों नहीं की गई। कक्षा की अपेक्षा करने से आपके मामले में पुन: प्रयोज्यता कम हो जाती है।
चरण

3
उस पंक्ति में जहां आप लक्ष्य मॉड्यूल में MyClass का निर्माण करते हैं, आप वर्ग नाम में एक निरर्थक संदर्भ जोड़ रहे हैं। यह पहले से ही संग्रहीत है expected_classइसलिए आप class_inst = getattr(py_mod,expected_name)()इसके बजाय कर सकते हैं ।
एंड्रयू

1
ध्यान दें कि यदि ठीक से मेल खाने वाली बाइट-संकलित फ़ाइल (प्रत्यय। Pyc या .pyo के साथ) मौजूद है, तो इसका उपयोग दिए गए स्रोत फ़ाइल को पार्स करने के बजाय किया जाएगाhttps://docs.python.org/2/library/imp.html#imp.load_source
cdosborn

1
ध्यान रखें: इस समाधान काम करता है; "": "imp पैकेज importlib के पक्ष में निंदा लंबित है पदावनत संस्करण 3.4 के बाद से।" "": हालांकि, imp मॉड्यूल आयात lib के पक्ष में पदावनत किया जा रहा है, इम्प के पृष्ठ देखें
रिकार्डो


15

आजकल आपको importlib का उपयोग करना चाहिए ।

एक स्रोत फ़ाइल आयात करें

डॉक्स वास्तव में उस के लिए एक नुस्खा प्रदान करते हैं, और यह प्रकार है:

import sys
import importlib.util

file_path = 'pluginX.py'
module_name = 'pluginX'

spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)

# check if it's all there..
def bla(mod):
    print(dir(mod))
bla(module)

एक पैकेज आयात करें

एक पैकेज आयात कर रहा है ( उदाहरण के लिए , pluginX/__init__.py) अपने वर्तमान dir के तहत वास्तव में स्पष्ट है:

import importlib

pkg = importlib.import_module('pluginX')

# check if it's all there..
def bla(mod):
    print(dir(mod))
bla(pkg)

3
sys.modules[module_name] = moduleअपने कोड के अंत में जोड़ें यदि आप import module_nameबाद में सक्षम होना चाहते हैं
डैनियल ब्रौन

@DanielBraun ऐसा करने से मुझे त्रुटि मिली> ModuleNotFoundError
Nam G VU

11

यदि आप इसे अपने स्थानीय लोगों में चाहते हैं:

>>> mod = 'sys'
>>> locals()['my_module'] = __import__(mod)
>>> my_module.version
'2.6.6 (r266:84297, Aug 24 2010, 18:46:32) [MSC v.1500 32 bit (Intel)]'

उसी के साथ काम करेंगे globals()


प्रलेखन के लिए निर्मित locals()समारोह स्पष्ट रूप से चेतावनी दी है कि "इस शब्दकोश की सामग्री को संशोधित नहीं किया जाना चाहिए"।
मार्टीन्यू

9

आप उपयोग कर सकते हैं exec:

exec("import myapp.commands.%s" % command)

मैं निष्पादन के माध्यम से मॉड्यूल को कैसे संभाल सकता हूं, ताकि मैं (इस उदाहरण में) .run () विधि को कॉल कर सकूं?
कामिल किसियल

5
फिर आप मॉड्यूल तक पहुँचने के लिए getattr (myapp.commands, कमांड) कर सकते हैं।
ग्रेग हेवगिल

1
... या as command_moduleआयात विवरण के अंत में जोड़ें और फिर करेंcommand_module.run()
ऑक्सफ़न

पायथन के कुछ संस्करण में 3+ निष्पादन को अतिरिक्त लाभ के साथ एक फ़ंक्शन में बदल दिया गया था, जिसके परिणामस्वरूप स्रोत में बनाया गया परिणाम स्थानीय लोगों में जमा हो जाता है () निष्पादन का तर्क ()। स्थानीय कोड ब्लॉक लोकल से संदर्भित निष्पादन को और अलग करने के लिए, आप अपना स्वयं का तानाशाही प्रदान कर सकते हैं, जैसे खाली एक और संदर्भ का उपयोग करके उस तानाशाही का उपयोग करें, या उस कार्य को अन्य कार्यों को निष्पादित करने के लिए पारित करें (स्रोत, gobals (), command1_dict .... प्रिंट (कमांड 1_डिक्ट ['somevarible'])
DevPlayer

3

@Monkut के समाधान के समान लेकिन पुन: प्रयोज्य और त्रुटि सहिष्णु यहाँ वर्णित http://stamat.wordpress.com/dynamic-module-import-in-python/ :

import os
import imp

def importFromURI(uri, absl):
    mod = None
    if not absl:
        uri = os.path.normpath(os.path.join(os.path.dirname(__file__), uri))
    path, fname = os.path.split(uri)
    mname, ext = os.path.splitext(fname)

    if os.path.exists(os.path.join(path,mname)+'.pyc'):
        try:
            return imp.load_compiled(mname, uri)
        except:
            pass
    if os.path.exists(os.path.join(path,mname)+'.py'):
        try:
            return imp.load_source(mname, uri)
        except:
            pass

    return mod

1

नीचे का टुकड़ा मेरे लिए काम आया:

>>>import imp; 
>>>fp, pathname, description = imp.find_module("/home/test_module"); 
>>>test_module = imp.load_module("test_module", fp, pathname, description);
>>>print test_module.print_hello();

यदि आप शेल-स्क्रिप्ट में आयात करना चाहते हैं:

python -c '<above entire code in one line>'

-2

उदाहरण के लिए, मेरे मॉड्यूल के नाम jan_module/ feb_module/ जैसे हैं mar_module

month = 'feb'
exec 'from %s_module import *'%(month)

-7

निम्नलिखित ने मेरे लिए काम किया:

import sys, glob
sys.path.append('/home/marc/python/importtest/modus')
fl = glob.glob('modus/*.py')
modulist = []
adapters=[]
for i in range(len(fl)):
    fl[i] = fl[i].split('/')[1]
    fl[i] = fl[i][0:(len(fl[i])-3)]
    modulist.append(getattr(__import__(fl[i]),fl[i]))
    adapters.append(modulist[i]())

यह फोल्डर 'मॉडस' से मॉड्यूल लोड करता है। मॉड्यूल में एकल वर्ग होता है जिसमें मॉड्यूल नाम के समान नाम होता है। जैसे फ़ाइल मोडस / modu1.py में शामिल है:

class modu1():
    def __init__(self):
        self.x=1
        print self.x

परिणाम गतिशील रूप से भरी हुई कक्षाओं की एक सूची है "एडेप्टर"।


13
कृपया टिप्पणियों में कोई कारण बताए बिना उत्तरों को दफन न करें। यह किसी की मदद नहीं करता है।
रीब

मैं जानना चाहता हूं कि यह खराब सामान क्यों है।
DevPlayer

मेरे जैसे ही, जब से मैं पायथन के लिए नया आया हूं और जानना चाहता हूं, यह बुरा क्यों है।
कोसमोस

5
यह बुरा नहीं है क्योंकि यह बुरा अजगर है, लेकिन यह भी सिर्फ आम तौर पर बुरा कोड है। क्या है fl? लूप की परिभाषा अत्यधिक जटिल है। पथ कठिन कोडित है (और उदाहरण के लिए, अप्रासंगिक)। यह हतोत्साहित अजगर ( __import__) का उपयोग कर रहा है , इसके fl[i]लिए वह सब क्या है ? यह मूल रूप से अपठनीय है, और किसी चीज के लिए अनावश्यक रूप से जटिल है जो कि सभी कठिन नहीं है - इसके एक-लाइनर के साथ शीर्ष मतदान जवाब देखें।
फिल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.