从子目录中的不同文件导入类

时间:2011-02-27 18:07:18

标签: python import

这是我正在使用的结构:

directory/
          script.py
          subdir/
                 __init__.py
                 myclass01.py
                 myclass02.py

我想要做的是在script.py中导入myclass01.pymyclass02.py中定义的类。如果我这样做:

from subdir.myclass01 import *

它适用于myclass01.py中定义的类。但是使用此解决方案,如果在subdir中的不同文件中定义了许多类,并且我想要导入所有这些类,那么我必须为每个文件键入一行。必须有一个捷径。我试过了:

from subdir.* import *

但它没有成功。

编辑:以下是文件的内容:

这是__init__.py(根据Apalala建议使用__all__):

__all__ = ['MyClass01','MyClass02']

这是myclass01.py

class MyClass01:
    def printsomething():
        print 'hey'

这是myclass02.py

class MyClass02:
    def printsomething():
        print 'sup'

这是script.py

from subdir import *
MyClass01().printsomething()
MyClass02().printsomething()

这是我尝试运行script.py时获得的回溯:

File "script.py", line 1, in <module>
    from subdir import *
AttributeError: 'module' object has no attribute 'MyClass01'

5 个答案:

答案 0 :(得分:12)

虽然在那里使用的名称与您问题的目录结构中显示的名称不同,但您可以使用我对标题为Namespacing and classes的问题的回答。此处显示的__init__.py也允许usepackage.py脚本以这种方式编写(package映射到您问题中的subdirClass1映射到myclass01 {1}}等):

from package import *

print Class1
print Class2
print Class3

修订版(已更新):

糟糕,对不起,我的其他答案中的代码并不能完全按照您的意愿行事 - 它只会自动导入任何包子模块的名称。要使它还从每个子模块导入命名属性,还需要几行代码。这是包的__init__.py文件的修改版本(也适用于Python 3.4.1):

def _import_package_files():
    """ Dynamically import all the public attributes of the python modules in this
        file's directory (the package directory) and return a list of their names.
    """
    import os
    exports = []
    globals_, locals_ = globals(), locals()
    package_path = os.path.dirname(__file__)
    package_name = os.path.basename(package_path)

    for filename in os.listdir(package_path):
        modulename, ext = os.path.splitext(filename)
        if modulename[0] != '_' and ext in ('.py', '.pyw'):
            subpackage = '{}.{}'.format(package_name, modulename) # pkg relative
            module = __import__(subpackage, globals_, locals_, [modulename])
            modict = module.__dict__
            names = (modict['__all__'] if '__all__' in modict else
                     [name for name in modict if name[0] != '_'])  # all public
            exports.extend(names)
            globals_.update((name, modict[name]) for name in names)

    return exports

if __name__ != '__main__':
    __all__ = ['__all__'] + _import_package_files()  # '__all__' in __all__

或者你可以将上面的内容放在一个单独的.py模块文件中,并在包目录__init__.py中使用它,如下所示:

if __name__ != '__main__':
    from ._import_package_files import *  # defines __all__
    __all__.remove('__all__')  # prevent export (optional)

无论你命名文件是什么,它都应该以{{1​​}}下划线字符开头,因此它不会递归地尝试_

答案 1 :(得分:6)

您最好的选择,虽然可能不是最好的风格,但是将所有内容导入到包的命名空间中:

# this is subdir/__init__.py
from myclass01 import *
from myclass02 import *
from myclass03 import *

然后,在其他模块中,您可以直接从包中导入所需内容:

from subdir import Class1

答案 2 :(得分:5)

我知道自从这个问题得到解答以来已经过了几个月了,但我一直在寻找同样的事情并且碰到了这个页面。我对所选择的答案并不是很满意,所以我最终编写了自己的解决方案,并认为我会分享它。这就是我想出的:

# NOTE: The function name starts with an underscore so it doesn't get deleted by iself
def _load_modules(attr_filter=None):
    import os

    curdir = os.path.dirname(__file__)
    imports = [os.path.splitext(fname)[0] for fname in os.listdir(curdir) if fname.endswith(".py")]

    pubattrs = {}
    for mod_name in imports:
        mod = __import__(mod_name, globals(), locals(), ['*'], -1)

        for attr in mod.__dict__:
            if not attr.startswith('_') and (not attr_filter or attr_filter(mod_name, attr)):
                pubattrs[attr] = getattr(mod, attr)

    # Restore the global namespace to it's initial state
    for var in globals().copy():
        if not var.startswith('_'):
            del globals()[var]

    # Update the global namespace with the specific items we want
    globals().update(pubattrs)

# EXAMPLE: Only load classes that end with "Resource"
_load_modules(attr_filter=lambda mod, attr: True if attr.endswith("Resource") else False)
del _load_modules # Keep the namespace clean

这只是从包目录中的所有.py文件导入*,然后只将公共文件拉入全局命名空间。此外,如果只需要某些公共属性,它允许过滤器。

答案 3 :(得分:0)

我用这个简单的方法:

  1. 将目录添加到系统路径,然后
  2. 该目录中的
  3. import modulefrom module import function1, class1
  4. 请注意,module只是*.py文件的名称,没有扩展部分。

    这是一个一般例子:

    import sys
    sys.path.append("/path/to/folder/")
    import module # in that folder
    

    在你的情况下,它可能是这样的:

    import sys
    sys.path.append("subdir/")
    import myclass01
    # or
    from myclass01 import func1, class1, class2 # .. etc
    

答案 4 :(得分:-2)

from subdir.* import *

你不能在'from'语句之后直接使用'*'。 你需要明确的进口。请查看有关导入和包的Python文档。