一般来说,(Python)项目是如何构建的? [英] Generally speaking, how are (Python) projects structured?

查看:50
本文介绍了一般来说,(Python)项目是如何构建的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在构建我的项目时,我有点不知所措.我尝试以合理的方式构建事物,但最终总是每天至少两次重组整个事物.诚然,我的项目不是很大,但我希望不必重组所有内容,只需一次性解决一些问题.

I'm a bit lost when it comes to structuring my project(s). I try to structure things in ways that make sense, but always end up restructuring the whole thing at least twice per day. Granted, my projects aren't very big, but I would love to not have to restructure everything and just settle on something for once.

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

I'll describe my current program to try to make sense of things. It's a graphical program with a database backend for calculating the price of sails. Not everything is written yet, but the user will be able to select a sail category and model from two dropdown menus. Depending on the category-model combination, the program will present checkboxes and spinboxes. These checkboxes and spinboxes, when changed, draw information from a database and present the price of having that checkbox checked or having a certain number (e.g., area in square metres) in the spinbox.

在当前形式下,该项目如下所示:

In its current form, the project looks like this:

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

进一步澄清.resources 包含在 Qt Designer 中制作的所有 .ui 文件.它们是描述 GUI 的 XML 文件.可以使用终端工具将它们转换为 Python 脚本,我已将其嵌入到 generate_gui.py 中..qrc 文件也是如此.generate_gui.py 将自动生成的文件放在 gui 文件夹中,带有前缀 ui_ 或后缀 _rc.database.db 当前是空的,但最终将用于保存价格和所有内容.

To further clarify. resources holds all .ui files made in Qt Designer. They are XML files that describe the GUI. They can be converted to Python scripts with a terminal tool, which I've embedded into generate_gui.py. The same goes for .qrc files. generate_gui.py places the autogenerated files in the gui folder with either prefix ui_ or suffix _rc. database.db is currently empty, but will eventually be used to hold prices and everything.

MainWindow.pyOptionsWidget.py 是 Python 文件,它们包含同名对象,去掉 .py 后缀.MainWindowOptionsWidget 保存在其显示表面中.两个对象都使用它们对应的 uirc 文件.

MainWindow.py and OptionsWidget.py are Python files that hold objects of the same name, minus the .py suffix. MainWindow holds OptionsWidget in its display surface. Both objects use their corresponding ui and rc files.

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

SailQt.pyw is the file that makes a MainWindow instance, tells it to show itself, and then tells (Py)Qt to enter its loop and take over from there. It's basically much like a .exe file of a lot of graphical applications in that it's a small file that gets the program running.

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

My initial guess was to place SailQt.pyw inside the sailqt folder. But then MainWindow.py suddenly needed access to a __version__ string. The only way I could figure out how to achieve that was to move SailQt.pyw to the root folder of my project, and to let MainWindow.py import sailqt.__version__. But considering that was the nth time I had to shuffle things around and redo lines in most files to account for that tiny shuffle, I decided to just ask here.

我的问题很清楚:

  • 一般来说,Python 项目是如何构建的?这个 pydoc 链接 很有帮助,但这对我来说更像是一个模块而不是实际的东西由用户执行.
  • 我的上述结构是否正确?
  • 回答这个问题会加分,因为它有点跑题了.为什么我可以做import os然后做os.system("sudo rm -rf/")之类的事情,但我不能做之类的事情导入sailqt然后执行sailqt.gui.generate_gui.generate()?
  • How are, in general, Python projects structured? This pydoc link was helpful, but that seems more like a module to me than something that is actually executed by a user.
  • Did I get the above structuring right?
  • Bonus points for answering this, as it's a bit off-topic. How come I can do import os and then do stuff like os.system("sudo rm -rf /"), but I can't do stuff like import sailqt and then do sailqt.gui.generate_gui.generate()?

推荐答案

让我们先解决最后一个问题,因为就构建 Python 项目而言,这是最重要的.一旦您弄清楚如何让导入在您的项目中正常工作,剩下的事情就会变得更容易处理.

Let's deal with your last question first, because it's the most important as far as structuring python projects is concerned. Once you've sorted out how to get the imports working correctly within your project, the rest becomes much easier to deal with.

要理解的关键是当前运行脚本的目录会自动添加到sys.pathstart.因此,如果您将 main.py 脚本(您当前调用的 SailQt.pyw)outside 放在包的顶层容器目录,它将保证包导入始终有效,无论脚本从何处执行.

The key thing to understand is that the directory of the currently running script is automatically added to the start of sys.path. So if you put your main.py script (what you're currently calling SailQt.pyw) outside of your package in a top-level container directory, it will guarantee that package imports will always work, no matter where the script is executed from.

所以一个最小的起始结构可能是这样的:

So a minimal starting structure might look like this:

project/
    main.py
    package/
        __init__.py
        app.py
        mainwindow.py

现在,因为 main.py 必须在顶级 python 包目录之外,它应该只包含最少量的代码(刚好足以获得程序启动).鉴于上述结构,这意味着仅此而已:

Now, because main.py must be outside of the top-level python package directory, it should contain only a minimal amout of code (just enough to get the program started). Given the above structure, that would mean not much more than this:

if __name__ == '__main__':

    import sys
    from package import app
    sys.exit(app.run())

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

The app module would contain most of the actual code necessary to initialize the program and set up the gui, which would be imported like this:

from package.mainwindow import MainWindow

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

and this same form of fully qualified import statement can be used from anywhere with the package. So, for example, with this slightly more complicated structure:

project/
    main.py
    package/
        __init__.py
        app.py
        mainwindow.py
        utils.py
        dialogs/
            search.py

search 模块可以像这样从 utils 模块导入一个函数:

the search module could import a function from the utils module like this:

 from package.utils import myfunc

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

On the specific issue of accessing the __version__ string: for a PyQt program, you could put the following at the top of the app module:

    QtGui.QApplication.setApplicationName('progname')      
    QtGui.QApplication.setApplicationVersion('0.1')

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

and then access the name/version later like this:

    name = QtGui.qApp.applicationName()
    version = QtGui.qApp.applicationVersion()

<小时>

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


The other issues with your current structure are mainly to do with maintaining separation between code files and resource files.

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

Firstly: the package tree should only contain code files (i.e. python modules). The resource files belong in the project directory (i.e. outside the package). Secondly: files containing code generated from resources (e.g. by pyuic or pyrcc) should probably go in a separate sub-package (this also makes it easy for your version control tool to exclude them). This would result in an overall project structure like this:

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

这里,Makefile(或等效文件)负责生成ui/rc文件、编译python模块、安装/卸载程序等.程序运行时所需的资源(如作为数据库文件),需要安装在您的程序知道如何找到的标准位置(例如 Linux 上的 /usr/share/progname/database.db 之类的东西).在安装时,Makefile 还需要生成一个可执行的 bash 脚本(或等效脚本),该脚本知道您的程序在哪里以及如何启动它.也就是说,类似于:

Here, the Makefile (or equivalent) is responsible for generating the ui/rc files, compiling the python modules, installing/uninstalling the program, etc. Resources needed by the program at runtime (such as the database file), will need to be installed in a standard location that your program knows how to find (e.g. something like /usr/share/progname/database.db on Linux). At installation-time, the Makefile will also need to generate an executable bash script (or equivalent) that knows where your program is and how to start it. That is, something like:

#!/bin/sh

exec 'python' '/usr/share/progname/main.py' "$@"

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

which would obviously need to be installed as /usr/bin/progname (or whatever).

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

This may seem like quite a lot to deal with at first, but of course the major benefit of finding a project structure that works well, is that you can re-use it for all future projects (and start to develop your own templates and tools for setting up and managing those projects).

这篇关于一般来说,(Python)项目是如何构建的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆