【问题标题】:Python - Intra-package importing when package modules are sometimes used as standalone?Python - 包模块有时用作独立时的包内导入?
【发布时间】:2017-01-04 13:37:29
【问题描述】:

对不起,如果这个问题已经使用我不知道要搜索的术语得到回答。

我有一个项目:

project1/
    class1.py
    class2.py

class2class1 导入一些东西,但每个都有自己的if __name__ == '__main__',它们使用我经常运行的各自的类。但是,我有第二个项目,它从project1 创建每个类的子类。所以我希望project1成为一个包,这样我就可以很好地将它导入project2

project2/
    project1/
        __init__.py
        class1.py
        class2.py
    subclass1.py
    subclass2.py

但是,我在导入时遇到了问题。如果我将project1 制作成一个包,然后在class2.py 内部,我想使用from project1.class1 import class1 导入class1.py 代码。这使project2 代码正确运行。但是现在当我尝试使用project1 不是作为一个包,而是直接从该目录中运行代码时,project1 代码失败(因为它不知道project1 是什么)。如果我将project1 设置为直接在该目录中工作(即class2 中的导入是from class1 import Class1),那么当尝试将project1 用作来自project2 的包时,此导入会失败。

有没有办法同时使用它(使用project1 作为一个包而不是作为一个包)?如果有办法,这是一种不鼓励的方式,我还是应该重组我的代码?关于我应该如何处理的其他建议?谢谢!

编辑

澄清一下,问题出现是因为subclass2 导入了class2,而class2 又导入了class1。根据class2 导入class1 的方式,导入将从project2project1 失败,因为一个人将project1 视为一个包,而另一个人将其视为工作目录。

编辑 2

我正在使用 Python 3.5。显然这适用于 Python 2,但不适用于我当前版本的 python。

【问题讨论】:

  • 不确定我是否遗漏了您请求的细微差别,但您应该能够使用from project1 import class1 将 project1 类导入 project2,然后通过 class1.function() 使用代码。每个文件中都有if __name__ == "__main__"应该没关系...然后将class1导入class2仍然是from class1 import function
  • @chrxr:当我尝试在project2 中导入class2 时出现问题。由于class2 导入class1,然后取决于我如何执行导入在class2 内,从project2 的角度来看,导入将失败(如果将其导入为from class1 import Class1)或@ 987654360@'s(如果我将其导入为from project1.class1 import class1)。这是因为有一个进口链。 subclass2 进口 class2 进口 class1.
  • 当你想运行一个子模块时,你应该使用-m 开关。 IE。而不是做python /path/to/my/package1/class1.py 你应该做python -m package1.class1 (显然你的package1 包应该在PYTHONPATH 或者你应该在父目录中)。顺便说一句:我只是避免你正在做的事情:清楚地分开类定义和脚本并且从不运行package1。编写一个 单独的 文件,从 package1 导入类并执行它必须做的事情......它更简单、更干净、更不容易出错。

标签: python python-3.x package python-import


【解决方案1】:

编辑 2:向 class2.py 添加代码以将父目录附加到 PYTHONPATH 以符合 Python3 模块导入的工作方式。

import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

删除了 Class1 的相对导入。

文件夹结构:

project2
  - class3.py
  - project1
    - __init__.py
    - class1.py
    - class2.py

project2/project1/class1.py

class Class1(object):
    def __init__(self):
        super(Class1, self).__init__()
        self.name = "DAVE!"

    def printname(self):
        print(self.name)

def run():
    thingamy = Class1()
    thingamy.printname()

if __name__ == "__main__":
    run()

project2/project1/class2.py

import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

from class1 import Class1

class Class2(Class1):
    def childMethod(self):
      print('Calling child method')

def run():
    thingamy = Class2()
    thingamy.printname()
    thingamy.childMethod()

if __name__ == "__main__":
    run()

project2/class3.py

from project1.class2 import Class2
from project1.class1 import Class1

class Class3(Class2):
    def anotherChildMethod(self):
      print('Calling another child method')

def run():
    thingamy = Class3()
    thingamy.printname()
    thingamy.anotherChildMethod()

if __name__ == "__main__":
    run()

通过此设置,class1、2 和 3 中的每一个都可以作为独立脚本运行。

【讨论】:

  • 哦,奇怪!这适用于 Python 2,但给出了我在 Python 3 中遇到的错误! (即ImportError: No module named 'class1')(更新打印语句时)我使用的是Python 3。让我确保在问题中知道这一点。我不知道这会有所作为。
  • 因此,换句话说,当我运行您刚刚在 Python 2 中发布的代码时,一切都按我的意愿运行。但是在 Python 3.5 中,我收到了导入错误(在我修复了 print 语句以适应 Python 3 语法之后)。除了打印语句,我没有调整代码。
  • 明白了!需要在 class2.py 中使用相对导入。这是在 Python3 中添加的,以消除导入位置的歧义。
  • 在 Python 3 中模块不再在导入文件的目录中搜索。
  • @chrxr 使用相对导入你不能再单独运行class2.py了。
【解决方案2】:

您可以从project2 文件夹内运行class2.py,即将当前工作目录设置为project2 文件夹:

user@host:.../project2$ python project1/class2.py

在看起来像这样的窗口上:

C:\...project2> python project1/class2.py

或者,您可以修改 class2.py 内的 python 路径:

import sys
sys.path.append(".../project2")

from project1.class1 import class1

或者类似地修改PYTHONPATH环境变量。

为了能够扩展您的项目并从subclass2.py 导入例如subclass1.py 中的某些内容,您应该考虑始终以project2 开始导入路径,例如在class2.py 中:

from project2.project1.class1 import class1

当然,您需要调整我刚刚展示的方法以匹配新路径。

【讨论】:

  • 感谢您的建议。不幸的是,project1 是一个完全独立的项目,通常不存储在 project2 中(它实际上只是一个 git 子模块)。它也以与 project2 没有联系的类似方式用于第三个项目。所以 project1 应该没有对 project2 的引用,并且应该对此一无所知。只有 project2 应该知道 project1。
  • 那么我展示的第一个方法并使用PYTHONPATH 环境变量应该仍然是有效的选项。
  • 你是对的,这会起作用,所以你得到了赞成票。但我不会接受它作为答案,因为从父目录运行代码和手动编辑 PYTHONPATH 都需要一些工作。代码可能会被队友使用,这两种方法都有点例外,而且不是超级直观。
  • 我对这个答案投了反对票,因为它提出了解决这个问题的错误方法。您应该执行python package1/class1.py,而是应该使用python 解释器的-m 开关并使用python -m package1.class1。这可以确保正确初始化包。不这样做可能导致难以调试错误(例如,如果您在class1.py 中使用pickle 或与之相关的任何东西,以建议的方式运行代码可能会破坏功能)。
猜你喜欢
  • 2012-09-25
  • 2019-11-22
  • 2021-06-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-25
  • 2020-03-06
  • 2013-12-28
  • 1970-01-01
相关资源
最近更新 更多