关于python 3.x:如何以优雅的方式导入我自己的模块?

How to import my own modules the elegant way?

关于从另一个子目录导入类,我正在努力解决一个虚拟问题,但找不到令人满意的解决方案。这里是上下文:我有一个根文件夹,我们称之为Project,它包含两个子文件夹,称为app和test。

在应用程序中,我有我的类文件,class1.py等等。在测试中,我有test_class1.py来主持单元测试课程。对我来说似乎是标准的文件夹结构。如何从test_class1.py导入class1?到目前为止,我在sys.path中添加了".../app",但它对我来说太难看了!我尝试过from ..app import class1和许多其他组合都没有成功。

第二个问题:python 3.6+中还需要__init__.py吗?谢谢你的帮助


1/关于您的第一个问题,根据我自己的经验,我将按照以下方式安排项目:

1
2
3
4
5
6
7
8
9
10
11
12
project/
  app/
   class1.py
   __init__.py
   ...
  test/
   context.py
   test_class1.py
   __init__.py
   ...
  setup.py
  ...

Obviously, these test modules must import your packaged module to test
it. You can do this a few ways:

  • Expect the package to be installed in site-packages.
  • Use a simple (but explicit) path modification to resolve the package properly.

I highly recommend the latter. Requiring a developer to run setup.py
develop to test an actively changing codebase also requires them to
have an isolated environment setup for each instance of the codebase.

To give the individual tests import context, create a tests/context.py
file:

context.py*应该引导测试上下文,如下所示:

1
2
3
4
5
6
7
8
import sys
import os

sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

import app
from app import class1
...

然后,在您的test_class1.py文件中,我将按如下方式导入测试类:

1
2
3
4
5
6
7
from unittest import TestCase
from .context import class1  # or from context.class1 import MyClass

class TestClass1(TestCase):

    def setUp(self):
        self.to_be_tested = class1.MyClass() # or MyClass()

2/关于第二个关于python 3.6+中是否需要uuu init_uuy文件的问题,我让您阅读以下现有答案:python 3中的包是否不需要u init .py?

可能有趣的参考文献:

  • https://docs.python-guide.org/writing/structure/存储库结构
  • https://docs.python-guide.org/writing/structure/测试套件
  • 使用典型的测试目录结构运行UnitTest
  • 对于一个python应用程序,最好的项目结构是什么?
  • https://packaging.python.org网站/

1
from app import class1

从3.3创建包不需要__init__.py。+


您可以在test_class1.py中执行以下操作

1
2
3
4
5
6
7
8
9
10
11
12
import os
import sys
import unittest

parent_dir ="/".join(sys.path[0].split("/")[:-1])    # On Linux
parent_dir ="\".join(sys.path[0].split("\")[:-1])  # On Windows

sys.path.append(parent_dir)

from app import class1

## bla bla

当你打电话给test_class1.py时,你需要做以下的事情:

1
python -m test.test_class1