【问题标题】:Packaging python with circular imports使用循环导入打包 python
【发布时间】:2012-01-12 20:16:55
【问题描述】:

我查看了以前的问题,但我的情况略有不同......

我有一个目录,其中包含几个 python 类,它们在必要时在这里和那里相互导入。我想开始将它们打包成更小的模块,主要是为了组织。包的中心组件设置了一个 wsgi 应用程序,然后附加模块为其提供功能(到目前为止,这非常有效,因为我可以在命令行上单独测试模块,然后将它们的输入连接到 Web 应用程序。)

我了解提供__init__.py 模块的工作原理、其命名空间以及何时释放控制权。我遇到的问题是在某些情况下模块会相互导入。

例如,我有一个 JSONEncoder 用作cls 参数,用于多次调用json.dumps() 此类几乎用于每个文件。如果我将其中一些模块移动到包中的子目录,我将如何“上一层”来导入 json 编码器?我需要将父目录放在每个文件的 PYTHONPATH 上吗?给编码器自己的目录,用一个单独的 __init__.py 文件,会更好吗?

或者,我是否最好放入一个函数来向下钻取当前工作目录下的所有目录并将它们添加到路径中?

目前包含所有代码的主目录本身并未打包...考虑到它们具有循环导入,将类似类迁移到子目录的最佳方法是什么?

编辑:

澄清:

我一直在开发的主要工作目录只是一个包含大约十个 .py 文件的常规目录,所有这些文件都包含名称类似于文件名的类。目前整个事情只是一个 .py 文件的 git repo。

-project
  search.py
  jsonencoder.py
  webapp.py
  modela.py
  modelb.py
  modelc.py

名字当然是为了举例。

现在据我了解(这可能是完全错误的),明智的做法是将这些模型打包在一起,对吗?

-project
  search.py
  jsonencoder.py
  webapp.py
  -models
    __init__.py
    modela.py
    modelb.py
    modelc.py

但是反过来,project 文件夹也需要__init__ 吗?使用jsonencoder的modela如何导入?

【问题讨论】:

  • “我有一个包含几个 python 类的目录”。这是不明智的。目录包含文件。目录也可以是 Python 包。文件是模块。模块包含类定义。你能澄清你的问题吗?
  • @S.Lott 编辑了一个例子

标签: python import namespaces


【解决方案1】:

答案很简单:

只需使用您需要的子模块的完全限定名称

例如,在

mybundle/test/__init__.py 

你可以排队

import mybundle.JSONEncoder
  • 它会做正确的事。

例如,给定这个模块结构:

├── mybundle
│   ├── __init__.py
│   ├── jsonencoder
│   │   ├── __init__.py
│   └── test
│       ├── __init__.py

文件定义如下:

[gwidion@powerpuff tmp]$ cat mybundle/__init__.py
import test

[gwidion@powerpuff tmp]$ cat mybundle/test/__init__.py
import mybundle.jsonencoder

[gwidion@powerpuff tmp]$ cat mybundle/jsonencoder/__init__.py
print 5

这行得通:

[gwidion@powerpuff tmp]$ python
Python 2.7.1 (r271:86832, Apr 12 2011, 16:15:16) 
[GCC 4.6.0 20110331 (Red Hat 4.6.0-2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import mybundle
5
>>> 

【讨论】:

  • 那么关键是在根目录中也有一个 init.py,它将冒泡到子模块并执行它们的初始化脚本。 test 子目录中的 init 如何知道 mybundle 在哪里?
  • 是的,在根目录上有一个__init__.py 很重要——不过它可以是空的(0 字节)。创建一个空的__init__.py 会使Python 将该目录视为一个模块,而将包含__init__.py 文件的其他目录视为该目录的子模块。从那时起,使用 import . 就可以了,如果 无论如何都可以被应用程序找到。 (而 只是你的根目录的名称)
【解决方案2】:

您可以尝试这样的事情(root 是您的工作目录):

/root
  - file_a.py
  - file_b.py
  /JSONEncoder 
    - __init__.py
    - JSONEncoder.py

__init__.py 为空白,或有pass 或评论或其他内容。 然后你可以(来自file_a.pyroot 中的任何内容):

from JSONEncoder import JSONEncoder

并且可以在file_a.py 中访问JSONEncoder。只要您的所有运行代码都驻留在/root 中,您就不需要触摸PYTHONPATH,而__init__.py 只需要在子目录中。这种类型的目录布局非常有用,因为您可以隐藏“正常工作”的代码并专注于您需要处理的代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-29
    • 2014-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-02
    • 2010-10-19
    相关资源
    最近更新 更多