首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何设置多包Python应用程序?

如何设置多包Python应用程序?
EN

Stack Overflow用户
提问于 2016-03-15 12:20:32
回答 1查看 916关注 0票数 3

我的第一个Python应用程序相当小,所有的代码都在一个目录中。所有模块都只是相互“导入local_module”。在主脚本上执行"chmod +x“并运行应用程序很容易。

但是现在我正在创建一个更大的命令行驱动的应用程序,我希望它会运行到数万行代码中。所以我想把代码分散到不同的包中。此应用程序仅在工作时在内部运行。目前我们仍然在使用Python2.6.6。看起来有几种方法可以构造事物:

  1. 我让主脚本完成了应用程序的工作: 导入__future__导入absolute_import 然后通过: python -m main_dir.sub_dir.main_script
  2. 看起来,我还可以更改Python环境变量,以便只调用main_script.py,或者通过主脚本中的一些内容进行调用,比如: sys.path.insert(0,os.path.join(THIS_DIR,'..'))

我觉得我没有足够的理解来判断什么是建立和使用多包应用程序的最佳方式。我一直在做各种各样的Google搜索,并找到了很多关于如何运行的参考资料,这似乎属于上面列出的两种基本方法。但是,我还没有找到建立一个50,000行Python应用程序的方法。

更新:

凯文谢谢你的回答。它帮助我提高了对Python包的理解,但我仍然有些困惑。

我创建了这个目录结构:

代码语言:javascript
复制
 my\_app
代码语言:javascript
复制
   \ sub\_package1
代码语言:javascript
复制
   \ sub\_package2  

在这三个目录中,我创建了一个空的__init__.py文件。

在my_app目录中,我用以下内容创建了my_main.py:

代码语言:javascript
复制
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))

同样在my_app中,我用以下方法创建了at_main_level.py:

代码语言:javascript
复制
def double_number(x):
  return 2 *x

最后,在my_app中我创建了at_main_level_also.py:

代码语言:javascript
复制
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:

代码语言:javascript
复制
def subtract_1 (x):
  return x - 1

和11分之1:

代码语言:javascript
复制
import sub1

def subtract1_twice(x):
  return sub1.subtract_1(sub1.subtract_1(x))

现在,当我运行my_main.py时,我得到了对我来说有意义的结果:

代码语言:javascript
复制
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时:

代码语言:javascript
复制
from ..sub_package1 import sub1

def subtract_2 (x):
  return sub1(sub1(x))

添加到my_main.py中

代码语言:javascript
复制
import sub_package2.sub2 

在我的主要职能结束时:

代码语言:javascript
复制
xMinus2 = sub_package2.sub2.subtract_2(x)
_my_print ("{0}-1 is {1}".format(x, xMinus2))

在运行my_main时,我得到以下信息:

代码语言:javascript
复制
[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

因此,我还不明白如何创建一个应用程序,其中一个包中的代码可以在另一个包中使用代码。

我该怎么做?

谢谢。

EN

回答 1

Stack Overflow用户

发布于 2016-03-15 20:58:44

创建多个包实际上与正确创建单个包并无区别。

不要混淆“您的代码所在的目录”和“是Python包的目录”。也就是说,您应该有一个目录,所有的包和模块都在其中运行--假设它是/users/henry/myappcode/。在该目录中,可能有一些目录是用来组织代码的Python包;不同的是,后面的目录总是出现在导入中(当您使用绝对导入时),而前者永远不会出现。只要您这样做,也不需要与sys.path混为一谈。

下面是如何使用正确的路径启动应用程序,以便导入能够正常工作:

  1. 入门的简单版本。你有这样的文件: my_app_main.py _app/__init__..py my_app/module1.py my_app/module2.py my_app/subpackage/.我的应用/..。 您可以在任何目录中使用绝对路径或相对路径像这样运行它: python /users/henry/myappcode/my_app_main.py 当您使用Python脚本的路径调用Python时,Python会自动将该脚本(而不是当前目录)的位置放在sys.path上,因此您的所有.py文件都将自动能够import my_app.module等等。
  2. 上面的缺点是它有一个与模块不同的“主脚本”,而不是在与您代码的其余部分相同的包中。您已经了解了python -m,因此在本例中使其工作的方法是: PYTHONPATH=/users/henry/myappcode python -m my_app.main 假设您创建的是my_app/main.py而不是上面的my_app_main.py
  3. 备选案文2很难看。使其美观的方法是使您的package可安装(setup.py)。使用entry_points选项,您可以自动创建一个shell脚本,它与上面的命令相当,但是用户只需要在安装后输入my_app。 如果您想要进行开发,而不必每次运行python setup.py install,但有一个方便的命令,那么只需编写您自己的shell脚本就可以指向您的代码。 #/bin/sh PYTHONPATH=/users/henry/myappcode exec python -m my_app.main "$@“

在my_app目录中,我用以下内容创建了my_main.py: 导入sub_package1.sub1

如果您执行'python _app/my_main.py‘,那么Python的路径将被设置为my_app不是一个包,它是一个包含顶级包的目录。这就是为什么以后的相对导入在relative import beyond toplevel package中失败的原因:您已经将sub_package1安排为一个toplevel包。

这里有一条一般规则:您决不能在命令行中命名包目录。您可以用-m命名一个包(上面的选项2和3),也可以调用一个不在包内的脚本(选项1)。

您的相对导入是正确的,但是它失败了,因为Python没有将my_app视为一个包。确保您遵循的是选项1(主脚本而不是 or my_app)或选项2 (main与-m一起启动)。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36011221

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档