โมดูลนำเข้าจากตัวแปรสตริง


183

ฉันกำลังทำงานกับเอกสาร (ส่วนบุคคล) สำหรับไลบรารี matplotlib (MPL) ที่ซ้อนกันซึ่งแตกต่างจาก MPL ที่จัดเตรียมไว้เองโดยแพ็คเกจ submodule ที่สนใจ ฉันกำลังเขียนสคริปต์ Python ซึ่งฉันหวังว่าจะทำให้การสร้างเอกสารอัตโนมัติจากการเปิดตัว MPL ในอนาคต
ฉันเลือก submodules / แพ็คเกจที่สนใจและต้องการแสดงรายการคลาสหลักที่จะสร้างรายการและประมวลผลด้วยpydoc

ปัญหาคือฉันไม่สามารถหาวิธีที่จะสั่งให้ Python โหลด submodule จากสตริงได้ นี่คือตัวอย่างของสิ่งที่ฉันพยายาม:

import matplotlib.text as text
x = dir(text)

.

i = __import__('matplotlib.text')
y = dir(i)

.

j = __import__('matplotlib')
z = dir(j)

และนี่คือการเปรียบเทียบ 3 รายการข้างบนผ่านทาง pprint:

ป้อนคำอธิบายรูปภาพที่นี่

ฉันไม่เข้าใจสิ่งที่โหลดในyวัตถุ - มันเป็นพื้นฐานmatplotlibบวกอย่างอื่น แต่ขาดข้อมูลที่ฉันต้องการและนั่นคือชั้นเรียนหลักจากmatplotlib.textแพคเกจ มันเป็นส่วนที่มีสีฟ้าบนหน้าจอ ( xรายการ)

โปรดอย่าแนะนำ Sphinx เป็นวิธีการอื่น


คุณช่วยอธิบายได้ไหมว่าทำไมคุณถึงต้องใช้__import__(str)มากกว่าimportstatemetn มาตรฐาน?
thesamet

เป็นเพราะฉันจะประมวลผลรายการที่เป็นซับโดเลชัน MPL และรับเส้นทางของวิธีการ
theta

9
@thesamet - c'mon - มีแนวคิดที่ไม่สิ้นสุดที่คุณต้องการใช้ฟังก์ชันนี้ เมื่อคุณมีการกำหนดค่าเกี่ยวกับใจความของไลบรารี่คุณสามารถโหลดได้ตามชื่อซึ่งไม่สามารถใช้ได้กับimportคำสั่ง นี่คือตัวอย่างหนึ่งของการใช้งาน: djangosnippets.org/snippets/3048
Tomasz Gandor

คำตอบ:


279

__import__ฟังก์ชั่นสามารถเป็นบิตยากที่จะเข้าใจ

หากคุณเปลี่ยน

i = __import__('matplotlib.text')

ถึง

i = __import__('matplotlib.text', fromlist=[''])

แล้วจะอ้างถึงimatplotlib.text

ใน Python 2.7 และ Python 3.1 หรือใหม่กว่าคุณสามารถใช้importlib:

import importlib

i = importlib.import_module("matplotlib.text")

บางบันทึก

  • หากคุณกำลังพยายามนำเข้าบางสิ่งจากโฟลเดอร์ย่อยเช่น./feature/email.pyรหัสจะมีลักษณะดังนี้importlib.import_module("feature.email")

  • คุณไม่สามารถนำเข้าอะไรก็ได้หากไม่มี__init__.pyในโฟลเดอร์ที่มีไฟล์ที่คุณพยายามนำเข้า


3
importlibควรใช้ได้กับ pypi สำหรับ <python2.7
Jeffrey Jose

50
สำหรับทุกคนที่มาที่นี่จาก Google ควรสังเกตว่าถ้าคุณกำลังพยายามนำเข้าบางสิ่งจากโฟลเดอร์ย่อย (เช่น./feature/email.py) รหัสจะมีลักษณะดังนี้importlib.import_module("feature.email")
Seanny123

11
สุดท้ายโปรดจำไว้ว่าคุณไม่สามารถนำเข้าสิ่งใด ๆ หากไม่มี__init__.pyในโฟลเดอร์ที่มีไฟล์ที่คุณพยายามนำเข้า
Seanny123

3
@mzjn นี่คือimport moduleNameที่โมดูลNameเป็นสตริง แล้วไงfrom moduleName import *ล่ะ
Nam G VU

2
เพิ่งพบคำตอบสำหรับคำถามของฉันที่นี่ในกรณีที่ใครต้องการมันstackoverflow.com/a/31306598/248616
Nam G VU

68

importlib.import_moduleคือสิ่งที่คุณกำลังมองหา ส่งคืนโมดูลที่อิมพอร์ต (ใช้ได้กับ Python เท่านั้น> = 2.7 หรือ 3.x):

import importlib

mymodule = importlib.import_module('matplotlib.text')

หลังจากนั้นคุณสามารถเข้าถึงทุกสิ่งในโมดูลในฐานะmymodule.myclassเป็นต้น


อีกทางเลือกหนึ่งคือการimp.load_source(..)ใช้impโมดูลตามที่แนะนำในคำตอบนี้stackoverflow.com/questions/67631/…
Evgeni Sergeev

5
@gecco นี่คือimport moduleNameที่ moduleName เป็นสตริง แล้วไงfrom moduleName import *ล่ะ
Nam G VU

6

ใช้เวลาพยายามนำเข้าโมดูลจากรายการและนี่คือเธรดที่ทำให้ฉันใช้งานได้มากที่สุด - แต่ฉันไม่เข้าใจการใช้ ___import____ -

ดังนั้นนี่คือวิธีการนำเข้าโมดูลจากสตริงและรับลักษณะการทำงานเดียวกับการนำเข้า และลอง / ยกเว้นกรณีข้อผิดพลาดด้วย :)

  pipmodules = ['pycurl', 'ansible', 'bad_module_no_beer']
  for module in pipmodules:
      try:
          # because we want to import using a variable, do it this way
          module_obj = __import__(module)
          # create a global object containging our module
          globals()[module] = module_obj
      except ImportError:
          sys.stderr.write("ERROR: missing python module: " + module + "\n")
          sys.exit(1)

และใช่สำหรับ python 2.7> คุณมีตัวเลือกอื่น - แต่สำหรับ 2.6 <ใช้งานได้


1

ฉันได้พัฒนาฟังก์ชั่นที่มีประโยชน์ 3 อย่างนี้:

def loadModule(moduleName):
    module = None
    try:
        import sys
        del sys.modules[moduleName]
    except BaseException as err:
        pass
    try:
        import importlib
        module = importlib.import_module(moduleName)
    except BaseException as err:
        serr = str(err)
        print("Error to load the module '" + moduleName + "': " + serr)
    return module

def reloadModule(moduleName):
    module = loadModule(moduleName)
    moduleName, modulePath = str(module).replace("' from '", "||").replace("<module '", '').replace("'>", '').split("||")
    if (modulePath.endswith(".pyc")):
        import os
        os.remove(modulePath)
        module = loadModule(moduleName)
    return module

def getInstance(moduleName, param1, param2, param3):
    module = reloadModule(moduleName)
    instance = eval("module." + moduleName + "(param1, param2, param3)")
    return instance

และทุกครั้งที่ฉันต้องการโหลดอินสแตนซ์ใหม่ฉันต้องโทรหา getInstance () ดังนี้:

myInstance = getInstance("MyModule", myParam1, myParam2, myParam3)

ในที่สุดฉันสามารถเรียกใช้ฟังก์ชันทั้งหมดภายในอินสแตนซ์ใหม่:

myInstance.aFunction()

เฉพาะที่นี่เท่านั้นคือการปรับแต่งรายการ params (param1, param2, param3) ของอินสแตนซ์ของคุณ


1

นอกเหนือจากการใช้วิธีการimportlibหนึ่งยังสามารถใช้execวิธีการนำเข้าโมดูลจากตัวแปรสตริง

ที่นี่ฉันแสดงตัวอย่างของการนำเข้าcombinationsวิธีการจากitertoolsแพคเกจโดยใช้execวิธีการ:

MODULES = [
    ['itertools','combinations'],
]

for ITEM in MODULES:
    import_str = "from {0} import {1}".format(ITEM[0],', '.join(str(i) for i in ITEM[1:]))
    exec(import_str)

ar = list(combinations([1, 2, 3, 4], 2))
for elements in ar:
    print(elements)

เอาท์พุท:

(1, 2)
(1, 3)
(1, 4)
(2, 3)
(2, 4)
(3, 4)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.