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方式是什么?我是否需要完全重新思考如何构建它的想法?我是在正确的轨道上吗?