Python 子包和命名空间

标签 python python-import python-packaging

我正在努力解决在我看来是一个非常基本和常见的问题,经过数小时的互联网搜索后我找不到任何答案的事实告诉我,我一定做错了什么......
我只是想找到一种优雅的方式来处理我的包的导入。
的背景 :
我的包裹结构如下:

mypackage/
    __init__.py
    model/
        __init__.py
        A.py
        B.py
    controllers/
        __init__.py
        A.py
        B.py

# mypackage/model/A.py
class A:
    def __init__(self):
        print("This is A's model.")
# mypackage/model/B.py
from mypackage.model.A import A as AModel
class B:
    def __init__(self):
        self._a_model = AModel()
        print("This is B's model.")

# mypackage/controllers/A.py
class A:
    def __init__(self):
        print("This is A's controller.")
# mypackage/controllers/B.py
from mypackage.controllers.A import A as AController
class B:
    def __init__(self):
        self._a = AController()
        print("This is B's controller.")
问题 :
两件事是真的这个设计困扰着我。
第一:我想使用命名空间
我真的不喜欢写作
from mypackage.controllers.A import A as AController
...
self._a = AController()
感觉很麻烦,而且不是很pythonic......
我更喜欢使用如下命名空间:
from mypackage import controllers
...
self._a = controllers.A.A()
但如果我尝试,我会得到 AttributeError: module 'mypackage.controllers' has no attribute 'A'第二:我真的不喜欢输入类的文件名
我真的不喜欢写作
from mypackage.controllers.A import A as AController
我会选择 :
from mypackage.controllers import A as AController
什么没有奏效
将所有内容放在一个文件中
我知道我可以通过将所有 Controller 的类(A 和 B)定义放在一个文件(controllers.py)中来得到我想要的,并对模型做同样的事情......
我读过几次,将多个类定义放在一个文件中是在 python 中很常见的事情......但对于大型单独的类,我不能。如果 A 和 B 是数百行并且彼此无关(除了作为 Controller 和模型),那么将它们的定义放在单个文件中是不可用的。
中使用导入初始化 .py 文件
确实可以解决我所有的问题...
除了那个 :
  • 它导致循环进口。 如您所见,我在 B 的模型中需要 A 的模型...因此,如果在我需要访问其中一个模型时导入所有模型,我将陷入恶性循环...
  • 它似乎不是很pythonic。 如果只是因为它迫使用户加载每个模块。

  • 我在这里...
    我的推理有什么问题?

    最佳答案

    Using imports in the __init__.py file


    这就是要走的路。
    对不起,如果它看起来对你来说太多样板,但如果你的项目很大,那就是需要的。
    至于循环导入问题:无论您编写导入,它都会启动
    __init__文件与否,只是后勤问题。
    如果在您的 __init__文件,你以正确的顺序编写导入,就不会有循环问题。
    IE。在您的 myproject/models/__init__.py你有:
    from .A import A as AModel
    from .B import B as BModel
    
    当然,您将 .py 文件命名为与类相同的名称对您没有帮助 - 如果您至少放开文件名中的大小写,您可以编写:
    from .a import A
    from .b import B
    
    否则,您可以这样做:
    import myproject.models.A
    import myproject.models.B
    
    A = myproject.models.A.A
    B = myproject.models.B.B
    
    为了能够使用“myproject.models.A”作为类:
    姓名A里面 __init__将覆盖模块对象
    同名。
    一文import myproject.models.A将进入模块,但通过这样做from myproject.models import A你得到了模块。
    如果这让人感到困惑......尽量不要为模块文件使用与类相同的名称。即使在忽略大小写的文件系统(如 Windows)中,您也会
    反正模棱两可。遵守约定:snake_case 中的模块名,CamelCase 中的类名
    回到循环导入问题:关键是在这个设计中,b.py仅在 a.py 之后读取已经导入,没有循环导入问题。
    这并不总是可能的 - 有时需要子模块之间的交叉引用。在这些情况下可以做的是移动 import进入
    函数或方法,而不是作为全局语句。这样,当执行导入时,引用的模块已经初始化。
    在您的示例中,这将是:
    mypackage.models.b.py
    # mypackage/model/B.py
    
    class B:
        def __init__(self):
            from mypackage.model.A import A as AModel
            self._a_model = AModel()
            print("This is B's model.")
    
    

    关于Python 子包和命名空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67609395/

    相关文章:

    Python嵌套导入 'ModuleNotFound'错误

    python - 确保 Python 中不存在 __init__ 函数

    python - Flask 的 -a 参数?

    python - 在 setup.cfg 中查找问题 |路径中看不到模块

    python - 如何在 Python 设置脚本中引入 importlib.resources

    python - read_csv 将大型 csv 文件字段加载为对象

    python - 与 python 的随机集成

    python - 当 DEBUG = False 时,Django 给出错误请求(400)

    python - 如何将数组值导出到 CSV 中的不同行?

    python - 如何导入模块但忽略包的 __init__.py?