如何很好地构建我的模块,以便他们可以看到彼此?

时间:2017-01-17 22:40:37

标签: python directory-structure

TL; DR版本:

如何在项目中有多个能够互相看到的子模块? Pythonically?

长版:

我正在寻找一种很好/正确的方法来构建一些Python代码。 (我主要使用2.7,但是 - 如果它不同 - 我也对3的响应感兴趣,我也使用它。)

基本上,它涉及应该能够看到对方的子模块......但我将在下面详细解释。

我可能只是没有使用正确的关键字进行搜索,但我在网上找到的所有内容都只是讨论了在子模块的单个“分支”中导入,而我希望能够导入“分支到 - ” - 科。” (有一个半例外,在下面引用。)

也许这不是Pythonic,我不知道。但后来我想知道处理这个问题的Python方法是什么。

由于专有原因,我没有详细介绍我的实际问题应用程序,我将描述一个几乎完全类似的问题:

赛车!

假设我正在塑造赛车及其所包含的各个部分,例如轮胎。

每个部分都被建模为一个对象,具有各种属性和标准API。这样就很容易想出一个新的轮胎类 - 并且 - 只要它符合API - 我就可以即插即用。

发动机或挡风玻璃等其他部件也是如此。

当然,有许多标准的实用程序函数,大多数都使用这些函数 - 可能是自定义数学函数或文件IO函数等。

(也许我有一个引擎数据的标准文件格式,并且一些引擎类型在这些文件中的一个或两个中读取以便给出结果。并且可能更进一步,相同的格式也用于其他数据,例如基于温度和湿度的轮胎刚度,因此轮胎也需要能够使用该文件IO功能。)

然后我有不同种类的模拟对象,这些模拟对象会填充赛车及其组件的实例,并执行某些计算以找出不同的东西。

然后我还有绘图仪对象,它们采用模拟对象并创建各种相关事物的图。

我可以很容易地将所有这些放在一个巨大的文件中,其中包括以下部分和伪代码:

# (1)  Utility functions

# (2)  Material_Rubber (abstract) class and (non-abstract) child classes
# (3)  Tire (abstract) class            and (non-abstract) child classes
# (4)  Windshield  (abstract) class     and (non-abstract) child classes

# ... AND SO ON ...

# (5)  Racecar (abstract) class         and (non-abstract) child classes
# (6)  Track (abstract) class           and (non-abstract) child classes
# (7)  Weather (abstract) class         and (non-abstract) child classes

# ... YOU GET THE IDEA ...

# (8)  Simulation (abstract) class      and (non-abstract) child classes
# (9)  Plotter (abstract) class         and (non-abstract) child classes

# (10) Instantiation of Material_Rubber, 
#                       Tire, 
#                       Windshield, 
#                       Racecar, 
#                       Track, and 
#                       Weather child classes which are appropriate for 
#                       the particular simulation I want to run, some of 
#                       them needing each other -- eg:
hard_rubber = Material_Rubber_Hard(42)
fast_tires = Tire_Fast(hard_rubber)
smooth_windshield = Windshield_Smooth(0.42)
fast_car = Racecar_Fast(
    tires = fast_tires, 
    windshield = smooth_windshield
)

# (11) Instantiation of Simulation child class, which is likely to be 
#      dependent upon most of the 'large concept level' instances above.
#      Something like:
sim = Simulation_Speed(
    car1 = fast_car, 
    car2 = medium_car, 
    track = normal_track, 
    weather = stormy_weather
)

# (12) Running of the simulation
sim.run()

# (13) Plotting of the simulation data
plot = Plotter_Speed(sim)

# (14) Plotting of data
plot.plot()

# And then of course there could be other things like saving of data.

所以是的,我可以把它放在一个大文件中,甚至是同一目录中的一堆文件。

但是我有很多理由不想这样做。

首先,因为它难看且难以阅读和查找内容。我宁愿把它拆分成单独的文件,这些文件在逻辑上分类到不同的目录中,并且可读。

其次,因为如果有人想要添加一个新的挡风玻璃类型,他们必须在代码中找到正确的位置并修改原始来源。我更喜欢有一个“插件”系统,我只需编写一个新文件,将其粘贴在“挡风玻璃”目录中,然后从我选择导入所有模块的任何脚本中获取它。

所以我更喜欢我的代码遍布目录结构,如下所示:

racecar_sim/
    |
    +-- run_script.py
    |
    +-- utils/
    |    |
    |    + __init__.py
    |
    +-- parts/
    |    |
    |    +-- materials/
    |    |    |
    |    |    +-- rubber/
    |    |    |    |
    |    |    |    +-- __init__.py
    |    |    |
    |    |    +-- glass/
    |    |         |
    |    |         +-- __init__.py
    |    |
    |    +-- tires/
    |    |    |
    |    |    +-- __init__.py
    |    |
    |    +-- windshields/
    |         |
    |         +-- __init__.py
    |
    +-- tracks/
    |    |
    |    +-- __init__.py
    |
    +-- weather/
    |    |
    |    +-- __init__.py
    |
    +-- cars/
    |    |
    |    +-- __init__.py
    |
    +-- simulations/
    |    |
    |    + __init__.py
    |
    +-- parts/
         |
         + __init__.py

这将以run_script.py可能包含以下内容的方式完成:

from utils import file_io_function_1
from parts.materials.rubber import Material_Rubber_Hard
from parts.windshields import Windshield_Smooth
from cars import Racecar_Fast
# ... ETC ...
from simulations import Simulation_Speed
from plotters import Plotter_Speed

hard_rubber = Material_Rubber_Hard(42)
fast_tires = Tire_Fast(hard_rubber)

smooth_windshield = Windshield_Smooth(0.42)

fast_car = Racecar_Fast(
    tires = fast_tires, 
    windshield = smooth_windshield
)

sim = Simulation_Speed(
    car1 = fast_car, 
    car2 = medium_car, 
    track = normal_track, 
    weather = stormy_weather
)
sim.run()

plot = Plotter_Speed(sim)
plot.plot()

但是,我不知道该怎么做,因为其中许多模块需要导入其他模块。

例如,我想创建一个始终使用特定类型Tire的{​​{1}},因此它从其构造函数中调用Rubber子类构造函数。

同样,他们中的大多数都想要导入Rubber模块。

这是“跨分支导入”我不知道如何设置,除非我安装到utils,我不想这样做。

另一个选项类似于为测试套件here详细说明的内容,但似乎有点hackish并且我不确定它是否适合(没有双关语意图)适用于测试套件以外的其他内容:< / p>

site-packages

我必须在每个子模块中执行此操作,使用正确的路径,每个新的即插即用文件都必须执行相同的操作,...请注意!

我也宁愿避免尽可能多的import os import sys sys.path.insert(0, os.path.abspath('..')) 内容。我宁愿上面例子中的setup.py可以简单地在没有任何设置的情况下运行,或者至少尽可能少。

那么正确的Pythonic方式是什么?我是否需要完全重新思考如何构建它的想法?我是在正确的轨道上吗?

0 个答案:

没有答案