如何设置多包Python应用程序?
我的第一个Python应用程序相当小,所有代码都在一个目录中。所有模块只是相互“导入本地_模块”。在主脚本上执行“chmod+x”并运行应用程序很容易 但现在我正在创建一个更大的命令行驱动的应用程序,我希望它能运行数万行代码。所以我想把代码分散在不同的包中。此应用程序仅在工作时在内部运行。目前我们仍在使用Python2.6.6。看起来有两种方法可以组织事情:如何设置多包Python应用程序?,python,Python,我的第一个Python应用程序相当小,所有代码都在一个目录中。所有模块只是相互“导入本地_模块”。在主脚本上执行“chmod+x”并运行应用程序很容易 但现在我正在创建一个更大的命令行驱动的应用程序,我希望它能运行数万行代码。所以我想把代码分散在不同的包中。此应用程序仅在工作时在内部运行。目前我们仍在使用Python2.6.6。看起来有两种方法可以组织事情: 我通过让主脚本执行以下操作使应用程序正常工作: import __future__ import absolute_import 然后
import __future__ import absolute_import
然后通过以下方式呼叫:
python -m main_dir.sub_dir.main_script
sys.path.insert(0, os.path.join(THIS_DIR,'..'))
凯文,谢谢你的回答。这有助于提高我对Python包的理解,但我仍然有点困惑 我创建了这个目录结构:
我的应用程序
\子包装1
\子包装2 在所有三个目录中,我都创建了一个空的uuu init_uuuuu.py文件 在目录my_app中,我使用以下内容创建了my_main.py:
import sys
import sub_package1.sub1
import sub_package1.sub11
import at_main_level
import at_main_level_also
def _my_print (someString):
sys.stdout.write("{0}\n".format(someString))
if __name__ == '__main__':
_my_print ("Learning about Python packages and applications.")
x = 3
doubleX = at_main_level.double_number(x)
_my_print ("Double of {0} is {1}".format(x, doubleX))
doubleDoubleX = at_main_level_also.double_double_number(x)
_my_print ("Double Double of {0} is {1}".format(x, doubleDoubleX))
xMinus1 = sub_package1.sub1.subtract_1(x)
_my_print ("{0}-1 is {1}".format(x, xMinus1))
xMinus1Twice = sub_package1.sub11.subtract1_twice(x)
_my_print ("{0}-2 is {1}".format(x, xMinus1Twice))
import sub_package1.sub1
此外,在我的_应用程序中,我在_main_level.py创建了以下内容:
def double_number(x):
return 2 *x
最后,在我的_应用程序中,我创建了_main_level_allow.py:
import at_main_level
def double_double_number(x):
return at_main_level.double_number(at_main_level.double_number(x))
然后在sub_package1中,我创建了sub1.py:
def subtract_1 (x):
return x - 1
和sub11.py:
import sub1
def subtract1_twice(x):
return sub1.subtract_1(sub1.subtract_1(x))
现在,当我运行我的_main.py时,我得到了对我有意义的结果:
Learning about Python packages and applications.
Double of 3 is 6
Double Double of 3 is 12
3-1 is 2
3-2 is 1
因此我可以编写代码:
1) 一个模块在顶层的另一个模块中使用代码。2) 其中,顶层模块可以使用子包中的代码,子包中的代码可以调用子包中另一个模块中定义的函数 但在sub_package2中,我创建sub2.py:
from ..sub_package1 import sub1
def subtract_2 (x):
return sub1(sub1(x))
添加到my_main.py
import sub_package2.sub2
在我的主要职能结束时:
xMinus2 = sub_package2.sub2.subtract_2(x)
_my_print ("{0}-1 is {1}".format(x, xMinus2))
当运行我的_main时,我得到以下信息:
[my_app]$ python my_main.py
Traceback (most recent call last):
File "./my_main.py", line 8, in <module>
import sub_package2.sub2
File "/home/hcate/work/temp/my_app/sub_package2/sub2.py", line 2, in <module>
from ..sub_package1 import sub1
ValueError: Attempted relative import beyond toplevel package
[my_app]$python my_main.py
回溯(最近一次呼叫最后一次):
文件“/my_main.py”,第8行,在
导入子_包2.sub2
文件“/home/hcate/work/temp/my_app/sub_package2/sub2.py”,第2行,在
从..子包1导入子包1
ValueError:尝试在顶级包之外进行相对导入
所以我还不知道如何创建一个应用程序,其中一个包中的代码可以使用另一个包中的代码
我应该做什么不同
谢谢。创建多个包实际上与正确创建单个包没有什么不同 永远不要混淆“代码所在的目录”和“Python包目录”。也就是说,您应该有一个目录,所有的包和模块都位于其中,比如说它是
/users/henry/myappcode/
。在该目录中,可能有一些目录是用于组织代码的Python包;不同之处在于,后一个目录总是出现在导入中(当您使用绝对导入时),而前一个目录永远不会出现。只要这样做,您就不必再去搞sys.path
了
以下是如何使用正确的路径启动应用程序,以便导入工作正常:
my_app_main.py
my_app/__init__.py
my_app/module1.py
my_app/module2.py
my_app/subpackage/...
my_app/...
您可以这样运行它,从任何目录,使用绝对或相对路径:
python /users/henry/myappcode/my_app_main.py
当您使用Python脚本的路径调用Python时,Python会自动将该脚本的位置(而不是当前目录)放在sys.path
上,因此您的所有.py
文件将自动能够导入my_app.module
等等
python-m
,因此在本例中使其工作的方法是:
PYTHONPATH=/users/henry/myappcode python -m my_app.main
假设您创建了my_app/main.py
,而不是如上所述的my_app\u main.py
setup.py
)。使用entry\u points
选项,您可以自动创建一个shell脚本,该脚本执行与上述命令相同的操作,但用户只需在安装后键入my\u app
如果您想进行开发,而不必每次都运行python setup.py install
,而是使用一个方便的命令,那么只需编写指向代码的shell脚本即可
#!/bin/sh
PYTHONPATH=/users/henry/myappcode exec python -m my_app.main "$@"
在目录my_app中,我使用以下内容创建了my_main.py:
import sys
import sub_package1.sub1
import sub_package1.sub11
import at_main_level
import at_main_level_also
def _my_print (someString):
sys.stdout.write("{0}\n".format(someString))
if __name__ == '__main__':
_my_print ("Learning about Python packages and applications.")
x = 3
doubleX = at_main_level.double_number(x)
_my_print ("Double of {0} is {1}".format(x, doubleX))
doubleDoubleX = at_main_level_also.double_double_number(x)
_my_print ("Double Double of {0} is {1}".format(x, doubleDoubleX))
xMinus1 = sub_package1.sub1.subtract_1(x)
_my_print ("{0}-1 is {1}".format(x, xMinus1))
xMinus1Twice = sub_package1.sub11.subtract1_twice(x)
_my_print ("{0}-2 is {1}".format(x, xMinus1Twice))
import sub_package1.sub1
如果执行“python my_app/my_main.py”,则设置python的路径,以使my_app不是一个包,而是一个包含顶级包的目录。这就是为什么您以后的相对导入会失败,因为相对导入超出了顶级包
:您已将子包1
安排为顶级包
这里有一条一般规则:决不能在命令行上命名包目录。您可以使用-m
(上面的选项2和3)命名包,也可以调用不在包内的脚本(选项1)
您的相对导入是正确的,但它失败了,因为Python没有将
my_app
视为一个包。确保您遵循选项1(主脚本非my_app
)或选项2(主脚本使用-m
启动)。Kevin,感谢您的回答。我仍然在为如何设置Python应用程序而挣扎