gpt4 book ai didi

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

转载 作者:太空宇宙 更新时间:2023-11-03 14:12:46 25 4
gpt4 key购买 nike

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

但现在我正在创建一个更大的命令行驱动的应用程序,我预计它会运行数万行代码。所以我想将代码分散到各个包中。此应用程序只会在工作时在内部运行。目前我们仍在使用 Python 2.6.6。看起来有几种构建事物的方法:

  1. 我通过让主脚本执行以下操作让应用程序正常工作:

     import __future__ import absolute_import

    然后通过以下方式调用它:

     python -m main_dir.sub_dir.main_script
  2. 看来我还可以更改 Python 路径环境变量,这样我就可以调用 main_script.py,或者通过主脚本中的某些内容,例如:

     sys.path.insert(0, os.path.join(THIS_DIR,'..'))

我觉得我没有足够的了解来判断什么是设置和使用多包应用程序的最佳方式。我一直在进行各种谷歌搜索,发现很多关于如何运行的引用资料,这些引用资料似乎属于上面列出的两种基本方法。但是我没有找到太多关于设置 50,000 行 Python 应用程序的信息。

更新:

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

我创建了这个目录结构:
我的应用
\子包1
\sub_package2

在所有三个目录中,我都创建了一个空的 __init__.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))

我还在 my_app 中创建了 at_main_level.py :

def double_number(x):
return 2 *x

最后在 my_app 中我创建了 at_main_level_also.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))

现在,当我运行 my_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))

运行 my_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

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

我应该做什么不同的事情?

谢谢。

最佳答案

创建多个包实际上与正确地创建单个包没有区别。

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

以下是如何使用正确的路径启动您的应用,以便导入工作:

  1. 入门的简单版本。你有这样的文件:

     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 文件都将自动能够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 很丑陋。使它漂亮的方法是使您的 Python 包可安装 (setup.py)。使用 entry_points 选项,您可以自动创建一个 shell 脚本,它执行与上述命令等效的操作,但用户只需在安装后键入 my_app

    如果你想进行开发而不需要每次都运行 python setup.py install,但有一个方便的命令,那么只需制作你自己的指向你的代码的 shell 脚本即可。

     #!/bin/sh
    PYTHONPATH=/users/henry/myappcode exec python -m my_app.main "$@"

In the directory my_app I created my_main.py with:

import sub_package1.sub1

如果您执行“python my_app/my_main.py”,那么 Python 的路径被设置为 my_app 不是包,它是一个包含顶级包的目录。这就是为什么您后来的相对导入失败并显示 relative import beyond toplevel package 的原因:您已安排 sub_package1 成为顶级包。

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

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

关于python - 如何设置多包 Python 应用程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36011221/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com