多级包,文件路径和子包/模块导入

时间:2018-04-21 20:32:24

标签: python python-2.7 ipython

我正在创建一个多级包,结构看起来像这样

test.py
main_package/
    sub_package1/
        tables/
            table1.json
            table2.json

        __init__.py # empty
        lib1.py

    sub_package2/
        tables/
            table21.json
            table22.json

        __init__.py # empty
        lib2

    __init__.py # empty
    common1.py
    common2.py
    master_table.json

目前,所有__init__.py都是空的。

main_package / master_table.json的内容

{
    "group1": {
        "base": "sub_package1/tables",
        "files": [
            "table1.json",
            "table2.json"
        ]
    },
    "group2": {
        "base": "sub_package2/tables",
        "files": [
             "table21.json",
             "table22.json"
        ]
    }
}

在main_package / common2.py

import json

class DataTables(object):
    # codes for making this class a Singleton omitted
    ...

    def _process_table(self, table)
        ...

    # will be called from __init__
    def _read_tables(self):
        # the following line throws IOError: file not found
        table_list = json.load(open('master_table.json'))

        for s, desc in table_list.items():
            for f in desc['files']:
                fname = desc['base'] + '/' + f

                # this line also expected to throw IOError
                self._process_table(json.load(open(fname)))

在test.py中

from main_package.common2 import DataTables

test = DataTables()

正如预期的那样,DataTable._read_tables()失败,因为解释器在test.py所在的目录中找不到master_table.json。如果common2.py直接运行,代码运行正常。

问题是如何以灵活的方式纠正这个问题,无论目录结构test.py实际位于何处(即在另一个目录结构中)。

另一个问题是我如何测试,例如,lib1.py通过直接运行它来取决于common1.py中列出的函数?

lib1.py中的

(这不起作用)

from ..common1 import foo

def this_is_in_lib1()
    ...
    foo()
    ...

ValueError: Attempted relative import in non-package

同时修改导入

from main_package.common1 import foo

从test.py运行它就像这样工作

from main_package.sub_package.lib1 import this_is_on_lib1

this_is_in_lib1()

由于

2 个答案:

答案 0 :(得分:1)

模块具有__file__属性,告诉您.py文件的路径。通常,

table1 = json.load(open(os.path.join(os.path.dirname(__file__), 'table1.json)))

在该目录中的.py文件中就足够了。

答案 1 :(得分:0)

关于直接运行lib1.py的第二个问题,请不要这样做。不要在包装内使用任意入口点。您的包将由客户端代码导入,例如test.py中的代码。导入包并从那里进行测试,如果无法识别某个内部模块,则需要在相应的__init__.py内导入其名称。或者将测试作为子包,只使用测试子包中的常用相对路径。