一般来说,(Python)项目是如何构建的?

Rub*_*ker 17 python qt structure pyqt

在构建我的项目时,我有点迷失.我尝试以有意义的方式构建事物,但总是每天至少两次重组整个事情.当然,我的项目不是很大,但我希望不必重新构建所有内容,只需坚持一次.

我将描述我当前的程序,试图理解事物.它是一个带有数据库后端的图形程序,用于计算风帆价格.并非所有内容都已编写,但用户可以从两个下拉菜单中选择帆类别和型号.根据类别 - 模型组合,程序将显示复选框和旋转框.这些复选框和旋转框在更改时从数据库中提取信息并显示在复选框中选中该复选框或具有特定数字(例如,平方米的面积)的价格.

在目前的形式,该项目看起来像这样:

COPYING
README.md
SailQt.pyw                    (Should program be called from here ...)
sailqt/
    __init__.py               (This holds a __version__ string)
    SailQt.pyw                (... or here?)
    gui/
        __init__.py
        MainWindow.py         (This needs access to a __version__ string)
        MainWindow_rc.py
        OptionsWidget.py
        ui_MainWindow.py
        ui_OptionsWidget.py
    resources/
        __init__.py
        database.db
        generate_gui.py
        MainWindow.ui
        MainWindow.qrc
        OptionsWidget.ui
        icons/
            logo.png
Run Code Online (Sandbox Code Playgroud)

进一步澄清.resources保存.ui在Qt Designer中创建的所有文件.它们是描述GUI的XML文件.可以使用我嵌入的终端工具将它们转换为Python脚本generate_gui.py.这同样适用于.qrc文件.generate_gui.py将自动生成的文件放在gui带有前缀ui_或后缀的文件夹中_rc.database.db目前是空的,但最终将用于持有价格和一切.

MainWindow.py并且OptionsWidget.py是包含相同名称的对象的Python文件,减去.py后缀.MainWindow保持OptionsWidget在其显示表面.这两个对象使用的是相应uirc文件.

SailQt.pyw是一个创建MainWindow实例的文件,告诉它显示自己,然后告诉(Py)Qt进入它的循环并从那里接管.它基本上就像.exe很多图形应用程序的文件,因为它是一个让程序运行的小文件.

我最初的猜测是放在文件夹SailQt.pyw里面sailqt.但后来MainWindow.py突然需要访问一个__version__字符串.我可以弄清楚如何实现这一目标的唯一方法是移动SailQt.pyw到我的项目的根文件夹,并让MainWindow.py导入sailqt.__version__.但是考虑到这是第n次我不得不在大多数文件中重新排列和重做行以解释那个微小的混乱,我决定在这里问一下.

我的问题很清楚:

  • 一般来说,Python项目是如何构建的?这个pydoc链接很有用,但对我而言,这似乎更像是一个模块,而不是用户实际执行的模块.
  • 我是否正确地完成了上述结构?
  • 回答这个问题的奖励点,因为它有点偏离主题.我怎么能做import os,然后做的事情os.system("sudo rm -rf /"),但我不能做的事情import sailqt,然后sailqt.gui.generate_gui.generate()呢?

ekh*_*oro 26

让我们先处理你的上一个问题,因为就构建python项目而言,它是最重要的.一旦你弄清楚如何让你的项目中的导入正常工作,其余的就更容易处理了.

了解事情的关键是,当前运行的脚本的目录会自动添加到开始sys.path.因此,如果您将包中的main.py脚本(当前正在调用的内容SailQt.pyw)放在顶级容器目录中,则无论执行脚本的位置如何,都将保证包导入始终有效.

所以最小的起始结构可能如下所示:

project/
    main.py
    package/
        __init__.py
        app.py
        mainwindow.py
Run Code Online (Sandbox Code Playgroud)

现在,因为main.py必须在外面顶级Python包目录中,它应该只包含最少的代码大写金额(只是足以让程序启动).鉴于上述结构,这意味着没有比这更多:

if __name__ == '__main__':

    import sys
    from package import app
    sys.exit(app.run())
Run Code Online (Sandbox Code Playgroud)

app模块将包含初始化程序和设置gui所需的大部分实际代码,这些代码将像这样导入:

from package.mainwindow import MainWindow
Run Code Online (Sandbox Code Playgroud)

并且可以从包的任何地方使用这种相同形式的完全限定的import语句.因此,例如,这个稍微复杂的结构:

project/
    main.py
    package/
        __init__.py
        app.py
        mainwindow.py
        utils.py
        dialogs/
            search.py
Run Code Online (Sandbox Code Playgroud)

search模块可以从模块导入一个函数,utils如下所示:

 from package.utils import myfunc
Run Code Online (Sandbox Code Playgroud)

关于访问__version__字符串的具体问题:对于PyQt程序,您可以将以下内容放在app模块的顶部:

    QtGui.QApplication.setApplicationName('progname')      
    QtGui.QApplication.setApplicationVersion('0.1')
Run Code Online (Sandbox Code Playgroud)

然后像这样访问名称/版本:

    name = QtGui.qApp.applicationName()
    version = QtGui.qApp.applicationVersion()
Run Code Online (Sandbox Code Playgroud)

您当前结构的其他问题主要与维护代码文件和资源文件之间的分离有关.

首先:包树应该只包含代码文件(即python模块).资源文件属于项目目录(即包外).其次:包含资源(例如pyuic或pyrcc)生成的代码的文件应该放在一个单独的子包中(这也使得版本控制工具可以轻松地排除它们).这将导致整个项目结构如下:

project/
    db/
        database.db
    designer/
        mainwindow.ui
    icons/
        logo.png
    LICENSE
    Makefile
    resources.qrc
    main.py
    package/
        __init__.py
        app.py
        mainwindow.py
        ui/
            __init__.py
            mainwindow_ui.py
            resources_rc.py
Run Code Online (Sandbox Code Playgroud)

这里,Makefile(或等效的)负责生成ui/rc文件,编译python模块,安装/卸载程序等.程序运行时所需的资源(如数据库文件)需要安装在程序知道如何查找的标准位置(例如/usr/share/progname/database.dbLinux上的内容).在安装时,Makefile还需要生成一个可执行的bash脚本(或等效的),它知道程序的位置以及如何启动它.就是这样的:

#!/bin/sh

exec 'python' '/usr/share/progname/main.py' "$@"
Run Code Online (Sandbox Code Playgroud)

这显然需要安装为/usr/bin/progname(或其他).

这一开始可能看起来有很多,但当然找到一个运行良好的项目结构的主要好处是,你可以将它重用于所有未来的项目(并开始开发自己的模板和工具)用于设置和管理这些项目).