如何动态导入模块类

时间:2014-04-26 19:55:31

标签: python import module

我有以下结构:

app.py

modules
    |
    -- __init__.py
    |
    -- update.py

我尝试从modules/update.py dynamicaly调用函数:

import sys

arguments = sys.argv
module = arguments[1]
command = arguments[2]
moduleObj = __import__('modules.'+module)            # returns module object "modules"
submodule = getattr(moduleObj, module)    # returns the module object "modules.update"
moduleClass = getattr(submodule, module)  # returns the class object "update"
    # this works because the class has the same name as the file it contains it.
    # if the names are different then you have to change that accordingly 
result = getattr(moduleClass, command) # returns the attribute with the name =command
print result()

但我发现错误:

  

文件" app.py",第12行,in       print result()TypeError:必须使用update instance作为第一个参数调用unbound方法test()(没有任何内容)

出了什么问题?请帮帮我!

ps:update.py代码:

import os

class update:
    def repositories(self):
        os.system('sudo apt-get update')

    def system(self):
        os.system('sudo apt-get -y upgrade')

    def distributive(self):
        os.system('sudo apt-get -y dist-upgrade')

    def all(self):
        self.repositories()
        self.system()
        self.distributive()

    def test(self):
        print 'test complete!'

2 个答案:

答案 0 :(得分:0)

我认为你传递的是这样的论点:

python app.py update attribute

所以你的程序解释如下:

getattr(__import__('modules.update.update'),command)()

由于您没有具有该名称的模块,因此导致导入错误。

如果我理解正确,您有以下文件结构:

app.py

modules
    |
    -- __init__.py
    |
    -- update.py

修改 让我假设为了解释,你的update.py包含:

class update(object):
    name = 'update_name'

现在位于app.py

import sys

arguments = sys.argv
module = arguments[1]
command = arguments[2]
moduleObj = __import__(module)            # returns module object "modules"
submodule = getattr(moduleObj, module)    # returns the module object "modules.update"
moduleClass = getattr(submodule, module)  # returns the class object "update"
    # this works because the class has the same name as the file it contains it.
    # if the names are different then you have to change that accordingly 
name_attr = getattr(moduleClass, command) # returns the attribute with the name =command

看看你添加了什么印刷品:

print moduleObj 
print submodule 
print moduleClass
print name_attr

您现在可以通过以下方式调用脚本:

python app.py update name 

,输出结果如下:

<module 'modules' from '<path>/modules/__init__.pyc'>
<module 'modules.update' from '<path>/modules/update.pyc'>
<class 'modules.update.update'>
update_name

我认为现在您可以操作代码,但是您希望获得任何您喜欢的对象,甚至可以将它们作为updatename之类的参数传递给它们。

修改

你不能调用unbounded方法,你需要创建该类的实例,然后调用该实例的方法,这就是错误所说的内容。 所以你需要做类似下面的例子:

import sys

arguments = sys.argv
module = arguments[1]
command = arguments[2]
moduleObj = __import__(module)            # returns module "modules"
submodule = getattr(moduleObj, module)    # returns the module "modules.update"
localInstance = submodule.update()           # create instance of class 'update'
localInstance.test()                         # call instance method

这将打印:

test complete!

<强> PS:

不鼓励对您的方法名称或变量(如systemall使用某些字词,更好地更改它们。

希望这会有所帮助。

答案 1 :(得分:0)

关于更新的问题:

更新代码中的错误是由于您需要在调用其方法之前创建类的实例:

result = getattr(moduleClass(), command)

(注意括号)。


我认为错误源于此:

moduleObj = __import__('modules.'+module)

当您在没有fromlist参数的情况下致电__import__时,它会返回左模式模块,而不是最右侧模块。为了更清楚,让我举个例子:

In [3]: __import__('xml.dom')
Out[3]: <module 'xml' from '/usr/lib/python2.7/xml/__init__.pyc'>

注意返回xml模块, xml.dom模块! 即使未返回xml.dom,也已导入它。您可以通过xml.dom词典访问sys.modules

In [11]: sys.modules['xml.dom']
Out[11]: <module 'xml.dom' from '/usr/lib/python2.7/xml/dom/__init__.pyc'>

要让__import__返回xml.dom模块,您需要使用fromlist参数:

In [4]: __import__('xml.dom', fromlist=[''])
Out[4]: <module 'xml.dom' from '/usr/lib/python2.7/xml/dom/__init__.pyc'>

有关__import__行为方式can be found here的原因的更多信息。

以下是修复代码的3种不同方法:

  • 使用fromlist

    moduleObj = __import__('modules.'+module, fromlist=[''])
    

    (分配给fromlist的内容并不重要,它只需要是一个 非空字符串列表。)

  • 使用sys.modules

    name = 'modules.'+module
    __import__(name)
    moduleObj = sys.modules[name]
    
  • 或者,使用importlib.import_module

    import importlib
    moduleObj = importlib.import_module('modules.'+module)
    

在这三个中,我认为第三个是最具可读性的。