Python项目工程文件组织结构指南

一、项目工程文件目录

一个典型的Python项目工程目录结构可以帮助你更好地组织代码、资源和测试,从而使得项目更加清晰和易于维护。

my_project/
│
├── my_project/                    # 项目的主代码包
│   ├── __init__.py                # 包初始化文件
│   ├── module_1.py                # 示例模块1
│   └── module_2.py                # 示例模块2
│
├── tests/                         # 测试代码目录
│   ├── __init__.py                # 测试包初始化文件
│   ├── test_module_1.py           # 模块1的单元测试
│   └── test_module_2.py           # 模块2的单元测试
│
├── docs/                          # 项目文档
│   └── ...                        # 文档文件或子目录
│
├── setup.py                       # 构建和安装脚本
├── pyproject.toml                 # 定义构建系统要求(PEP 518)
├── requirements.txt               # 列出项目依赖
├── README.md                      # 项目说明文档
├── LICENSE                        # 许可证信息
└── .gitignore                     # Git版本控制忽略规则

目录和文件说明

  • my_project/:这是你的Python项目的主要源代码所在的地方。每个模块可以是单独的.py文件或者更复杂的子包。
  • tests/:这个目录用于存放所有与项目相关的测试代码。保持测试代码独立于源代码有助于保持代码的整洁性。
  • docs/:这里存放项目的文档资料,可以包括使用指南、API文档等。
  • setup.py 和 pyproject.toml:这两个文件用于定义如何打包你的项目以及它的依赖关系。setup.py是传统的配置文件,而pyproject.toml是根据PEP 518引入的新标准。
  • requirements.txt:列出项目依赖的所有外部库及其版本,便于在其他环境中复现项目的依赖环境。
  • README.md:提供项目的简要介绍、安装步骤、使用方法等信息。
  • LICENSE:包含项目的开源许可协议文本。
  • .gitignore:指定Git不应跟踪的文件模式,通常包括编译生成的文件、日志文件、本地配置等。
  • 二、模块

    在初步学习python之前我们基本上是用命令行通过 python 解释器来编程,如果你从 Python 解释器退出再进入,那么你定义的所有的方法和变量就都消失了。

    为此 Python 提供了一个办法,把这些定义存放在文件中,为一些脚本或者交互式的解释器实例使用,这个文件被称为模块。一个.py文件就称之为一个模块(Module)。

    模块的作用

  • 代码复用:将常用的功能封装到模块中,可以在多个程序中重复使用。
  • 命名空间管理:模块可以避免命名冲突,不同模块中的同名函数或变量不会互相干扰。
  • 代码组织:将代码按功能划分到不同的模块中,使程序结构更清晰。
  • 1.典型python文件

    #!/usr/bin/python3
    # 文件名: hello.py
    # -*- coding: utf-8 -*-
    
    ' a test module '
    
    __author__ = 'Michael Liao'
    import sys
     
    print('命令行参数如下:')
    for i in sys.argv:
       print(i)
    print('\n\nPython 路径为:', sys.path, '\n')
    
    Shebang (#! /usr/bin/python3):

    这一行被称为Shebang或hashbang,它位于文件的绝对开头。它的作用是指定该脚本使用的解释器路径。在这个例子中,#!/usr/bin/python3告诉操作系统这个脚本应该使用Python 3来执行。这对于在Unix、Linux和macOS等系统上直接运行脚本特别有用。

    编码声明 (# – coding: utf-8 –):

    这行注释指定了源代码文件的字符编码格式为UTF-8。虽然Python 3默认使用UTF-8编码,但明确指定编码可以避免一些潜在的编码问题,尤其是在处理非ASCII字符时。

    模块文档字符串 (’ a test module '):

    紧接在文件头部之后的是一个字符串字面量,它通常被用作模块级别的文档字符串(docstring)。这是对整个模块的目的和功能的简短描述,有助于其他开发者快速了解该模块的作用。

    作者信息 (author = ‘Michael Liao’):

    __author__是一个特殊变量,用于标识脚本或模块的作者。这是一种约定俗成的做法,尽管不是必须的,但它有助于识别模块的创作者或维护者。

    导入模块 (import sys):

    import sys语句用于导入Python标准库中的sys模块。通过导入这个模块,你可以访问与Python解释器及其环境交互的功能,比如命令行参数(sys.argv)和Python搜索路径(sys.path)。

    2.引入模块

    (1)import 语句

    想使用 Python 源文件,只需在另一个源文件里执行 import 语句,语法如下:

    import module1[, module2[,... moduleN]
    

    当解释器遇到 import 语句,如果模块在当前的搜索路径就会被导入。

    搜索路径时一个解释器会先进行搜索的所有目录的列表。如想要导入模块 support,需要把命令放在脚本的顶端:

    #!/usr/bin/python3
    # Filename: support.py
     
    def print_func( par ):
        print ("Hello : ", par)
        return
    

    test.py 引入 support 模块:

    #!/usr/bin/python3
    # Filename: test.py
     
    # 导入模块
    import support
     
    # 现在可以调用模块里包含的函数了
    support.print_func("World")
    
    (2)模块的搜索路径

    当导入一个模块时,Python 会按照以下顺序查找模块:

    1. 当前目录。
    2. 环境变量 PYTHONPATH 指定的目录。
    3. Python 标准库目录。
    4. .pth 文件中指定的目录。
    >>> ['/root', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/usr/local/lib/python3.4/dist-packages', '/usr/lib/python3/dist-packages'] 
    
    (3)from … import 语句

    Python 的 from 语句让你从模块中导入一个指定的部分到当前命名空间中,语法如下:

    from modname import name1[, name2[, ... nameN]]
    

    例如,要导入模块 fibo 的 fib 函数,使用如下语句:

    # Filename: fibo.py
    # 斐波那契(fibonacci)数列模块
     
    def fib(n):    # 定义到 n 的斐波那契数列
        a, b = 0, 1
        while b < n:
            print(b, end=' ')
            a, b = b, a+b
        print()
     
    def fib2(n): # 返回到 n 的斐波那契数列
        result = []
        a, b = 0, 1
        while b < n:
            result.append(b)
            a, b = b, a+b
        return result
    
    >>> from fibo import fib, fib2
    >>> fib(500)
    1 1 2 3 5 8 13 21 34 55 89 144 233 377
    

    这个声明不会把整个fibo模块导入到当前的命名空间中,它只会将fibo里的fib函数引入进来。

    (4)给模块起别名

    使用 as 关键字为模块或函数起别名:

    import numpy as np  # 将 numpy 模块别名设置为 np
    from math import sqrt as square_root  # 将 sqrt 函数别名设置为 square_root
    
    (5)from … import * 语句

    把一个模块的所有内容全都导入到当前的命名空间也是可行的,只需使用如下声明:

    from modname import *
    

    这提供了一个简单的方法来导入一个模块中的所有项目。

    不推荐,容易引起命名冲突。

    (6)__name__ 属性

    当我们在命令行运行模块文件时,Python解释器把一个特殊变量__name__置为__main__,而如果在其他地方导入该模块时,if判断将失败,因此,这种if测试可以让一个模块通过命令行运行时执行一些额外的代码,最常见的就是运行测试。

    if __name__=='__main__':
        test()
    

    一个模块被另一个程序第一次引入时,其主程序将运行。

    #!/usr/bin/python3
    # Filename: using_name.py
    
    if __name__ == '__main__':
       print('程序自身在运行')
    else:
       print('我来自另一模块')
    运行输出如下:
    

    如果我们想在模块被引入时,模块中的某一程序块不执行,我们可以用 __name__ 属性来使该程序块仅在该模块自身运行时执行。

    $ python using_name.py
    程序自身在运行
    $ python
    >>> import using_name
    我来自另一模块
    >>>
    

    3.标准模块

    以下是一些 Python3 标准库中的模块:

  • os 模块:os 模块提供了许多与操作系统交互的函数,例如创建、移动和删除文件和目录,以及访问环境变量等。

  • sys 模块:sys 模块提供了与 Python 解释器和系统相关的功能,例如解释器的版本和路径,以及与 stdin、stdout 和 stderr 相关的信息。

  • time 模块:time 模块提供了处理时间的函数,例如获取当前时间、格式化日期和时间、计时等。

  • datetime 模块:datetime 模块提供了更高级的日期和时间处理函数,例如处理时区、计算时间差、计算日期差等。

  • random 模块:random 模块提供了生成随机数的函数,例如生成随机整数、浮点数、序列等。

  • math 模块:math 模块提供了数学函数,例如三角函数、对数函数、指数函数、常数等。

  • re 模块:re 模块提供了正则表达式处理函数,可以用于文本搜索、替换、分割等。

  • json 模块:json 模块提供了 JSON 编码和解码函数,可以将 Python 对象转换为 JSON 格式,并从 JSON 格式中解析出 Python 对象。

  • urllib 模块:urllib 模块提供了访问网页和处理 URL 的功能,包括下载文件、发送 POST 请求、处理 cookies 等。

  • (1)操作系统接口

    os 模块提供了不少与操作系统相关联的函数,例如文件和目录的操作。

    import os
    
    # 获取当前工作目录
    current_dir = os.getcwd()
    print("当前工作目录:", current_dir)
    
    # 列出目录下的文件
    files = os.listdir(current_dir)
    print("目录下的文件:", files)
    
    (2)文件通配符

    glob 模块提供了一个函数用于从目录通配符搜索中生成文件列表:

    >>> import glob
    >>> glob.glob('*.py')
    ['primes.py', 'random.py', 'quote.py']
    
    (3)命令行参数

    通用工具脚本经常调用命令行参数。这些命令行参数以链表形式存储于 sys 模块的 argv 变量。例如在命令行中执行 “python demo.py one two three” 后可以得到以下输出结果:

    >>> import sys
    >>> print(sys.argv)
    ['demo.py', 'one', 'two', 'three']
    

    三、命名空间

    命名空间(Namespace)是从名称到对象的映射,大部分的命名空间都是通过 Python 字典来实现的。

    命名空间提供了在项目中避免名字冲突的一种方法。各个命名空间是独立的,没有任何关系的,所以一个命名空间中不能有重名,但不同的命名空间是可以重名而没有任何影响。

    一般有三种命名空间:

  • 内置名称(built-in names), Python 语言内置的名称,比如函数名 abs、char 和异常名称 BaseException、Exception 等等。
  • 全局名称(global names),模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
  • 局部名称(local names),函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是)

  • Python 的查找顺序为:局部的命名空间 -> 全局命名空间 -> 内置命名空间。

    1.命名空间的生命周期

    命名空间的生命周期取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束。

    因此,我们无法从外部命名空间访问内部命名空间的对象。

    # var1 是全局名称
    var1 = 5
    def some_func(): 
      
        # var2 是局部名称
        var2 = 6
        def some_inner_func(): 
      
            # var3 是内嵌的局部名称
            var3 = 7
    

    如下图所示,相同的对象名称可以存在于多个命名空间中。

    四、作用域

    作用域就是一个 Python 程序可以直接访问命名空间的正文区域。

    在一个 python 程序中,直接访问一个变量,会从内到外依次访问所有的作用域直到找到,否则会报未定义的错误。

    Python 中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。

    变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。

    1.作用域的分类

    Python 的作用域一共有 4 种,分别是:

    有四种作用域:

  • L(Local):最内层,包含局部变量,比如一个函数/方法内部。
  • E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。
  • G(Global):当前脚本的最外层,比如当前模块的全局变量。
  • B(Built-in): 包含了内建的变量/关键字等,最后被搜索。
  • LEGB 规则(Local, Enclosing, Global, Built-in):Python 查找变量时的顺序是: L –> E –> G –> B。

  • Local:当前函数的局部作用域。
  • Enclosing:包含当前函数的外部函数的作用域(如果有嵌套函数)。
  • Global:当前模块的全局作用域。
  • Built-in:Python 内置的作用域。
    在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内置中找。
  • g_count = 0  # 全局作用域
    def outer():
        o_count = 1  # 闭包函数外的函数中
        def inner():
            i_count = 2  # 局部作用域
    

    2.全局变量和局部变量

    定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。

    局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。

    在函数内部声明的变量只在函数内部的作用域中有效,调用函数时,这些内部变量会被加入到函数内部的作用域中,并且不会影响到函数外部的同名变量,如下实例:

    #!/usr/bin/python3
     
    total = 0 # 这是一个全局变量
    # 可写函数说明
    def sum( arg1, arg2 ):
        #返回2个参数的和."
        total = arg1 + arg2 # total在这里是局部变量.
        print ("函数内是局部变量 : ", total)
        return total
     
    #调用sum函数
    sum( 10, 20 )
    print ("函数外是全局变量 : ", total)
    

    3.global 和 nonlocal关键字

    当内部作用域想修改外部作用域的变量时,就要用到 global 和 nonlocal 关键字了。

    以下实例修改全局变量 num:

    #!/usr/bin/python3
     
    num = 1
    def fun1():
        global num  # 需要使用 global 关键字声明
        print(num) 
        num = 123
        print(num)
    fun1()
    print(num)
    
    # 以上实例输出结果:
    1
    123
    123
    

    如果要修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量则需要 nonlocal 关键字了,如下实例:

    #!/usr/bin/python3
     
    def outer():
        num = 10
        def inner():
            nonlocal num   # nonlocal关键字声明
            num = 100
            print(num)
        inner()
        print(num)
    outer()
    
    # 以上实例输出结果:
    100
    100
    
    总结
  • 全局变量在函数外部定义,可以在整个文件中访问。
  • 局部变量在函数内部定义,只能在函数内访问。
  • 使用 global 可以在函数中修改全局变量。
  • 使用 nonlocal 可以在嵌套函数中修改外部函数的变量。
  • 4.模块间公开与私有的作用域

    在一个模块中,我们可能会定义很多函数和变量,但有的函数和变量我们希望给别人使用,有的函数和变量我们希望仅仅在模块内部使用。

    类似java中publicprivate修饰符,而在Python中没有修饰符关键字,是通过_前缀来实现的。

    正常的函数和变量名是公开的(public),可以被直接引用,比如:abc,x123,PI等;

    类似__xxx__这样的变量是特殊变量,可以被直接引用,但是有特殊用途,比如上面的__author____name__就是特殊变量,hello模块定义的文档注释也可以用特殊变量__doc__访问,我们自己的变量一般不要用这种变量名;

    类似_xxx__xxx这样的函数或变量就是非公开的(private),不应该被直接引用,比如_abc__abc等;

    之所以我们说,private函数和变量“不应该”被直接引用,而不是“不能”被直接引用,是因为Python并没有一种方法可以完全限制访问private函数或变量,但是,从编程习惯上不应该引用private函数或变量。

    private函数或变量不应该被别人引用,那它们有什么用呢?请看例子:

    def _private_1(name):
        return 'Hello, %s' % name
    
    def _private_2(name):
        return 'Hi, %s' % name
    
    def greeting(name):
        if len(name) > 3:
            return _private_1(name)
        else:
            return _private_2(name)
    

    我们在模块里公开greeting()函数,而把内部逻辑用private函数隐藏起来了,这样,调用greeting()函数不用关心内部的private函数细节,这也是一种非常有用的代码封装和抽象的方法,即:

    外部不需要引用的函数全部定义成private,只有外部需要引用的函数才定义为public

    五、包

    如果不同的人编写的模块名相同怎么办?为了避免模块名冲突,Python又引入了按目录来组织模块的方法,称为包(Package)

    包是一种管理 Python 模块命名空间的形式,采用"点模块名称"。

    比如一个模块的名称是 A.B, 那么他表示一个包 A中的子模块 B

    举个例子,一个abc.py的文件就是一个名字叫abc的模块,一个xyz.py的文件就是一个名字叫xyz的模块。

    现在,假设我们的abcxyz这两个模块名字与其他模块冲突了,于是我们可以通过包来组织模块,避免冲突。方法是选择一个顶层包名,比如mycompany,按照如下目录存放:

    mycompany
    ├─ __init__.py
    ├─ abc.py
    └─ xyz.py
    

    引入了包以后,只要顶层的包名不与别人冲突,那所有模块都不会与别人冲突。现在,abc.py模块的名字就变成了mycompany.abc,类似的,xyz.py的模块名变成了mycompany.xyz

    就好像使用模块的时候,你不用担心不同模块之间的全局变量相互影响一样,采用点模块名称这种形式也不用担心不同库之间的模块重名的情况。

    请注意,每一个包目录下面都会有一个__init__.py的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录,而不是一个包。

    __init__.py可以是空文件,也可以有Python代码,因为__init__.py本身就是一个模块,而它的模块名就是mycompany

    最简单的情况,放一个空的 :file:__init__.py就可以了。当然这个文件中也可以包含一些初始化代码或者为__all__变量赋值。

    1.案例分析

    不妨假设你想设计一套统一处理声音文件和数据的模块(或者称之为一个"包")。

    现存很多种不同的音频文件格式(基本上都是通过后缀名区分的,例如: .wav,:file:.aiff,:file:.au,),所以你需要有一组不断增加的模块,用来在不同的格式之间转换。

    并且针对这些音频数据,还有很多不同的操作(比如混音,添加回声,增加均衡器功能,创建人造立体声效果),所以你还需要一组怎么也写不完的模块来处理这些操作。

    这里给出了一种可能的包结构(在分层的文件系统中):

    sound/                          顶层包
          __init__.py               初始化 sound 包
          formats/                  文件格式转换子包
                  __init__.py
                  wavread.py
                  wavwrite.py
                  aiffread.py
                  aiffwrite.py
                  auread.py
                  auwrite.py
                  ...
          effects/                  声音效果子包
                  __init__.py
                  echo.py
                  surround.py
                  reverse.py
                  ...
          filters/                  filters 子包
                  __init__.py
                  equalizer.py
                  vocoder.py
                  karaoke.py
                  ...
    
    

    在导入一个包的时候,Python 会根据 sys.path 中的目录来寻找这个包中包含的子目录。

    2.如何导入包中的内容?

    (1)每次导入一个模块

    用户可以每次只导入一个包里面的特定模块,比如:

    import sound.effects.echo
    

    这将会导入子模块:sound.effects.echo。 他必须使用全名去访问:

    sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)
    
    (2)导入子模块

    还有一种导入子模块的方法是:

    from sound.effects import echo
    

    这同样会导入子模块: echo,并且他不需要那些冗长的前缀,所以他可以这样使用:

    echo.echofilter(input, output, delay=0.7, atten=4)
    
    (3)导入函数变量

    还有一种变化就是直接导入一个函数或者变量:

    from sound.effects.echo import echofilter
    

    同样的,这种方法会导入子模块: echo,并且可以直接使用他的 echofilter() 函数:

    echofilter(input, output, delay=0.7, atten=4)
    

    注意当使用 from package import item 这种形式的时候,对应的 item 既可以是包里面的子模块(子包),或者包里面定义的其他名称,比如函数,类或者变量。

    import 语法会首先把 item 当作一个包定义的名称,如果没找到,再试图按照一个模块去导入。如果还没找到,抛出一个 :exc:ImportError 异常。

    反之,如果使用形如 import item.subitem.subsubitem 这种导入形式,除了最后一项,都必须是包,而最后一项则可以是模块或者是包,但是不可以是类,函数或者变量的名字。

    3.从一个包中导入*

    如果我们使用 from sound.effects import * 会发生什么呢?

    Python 会进入文件系统,找到这个包里面所有的子模块,然后一个一个的把它们都导入进来。

    但这个方法在 Windows 平台上工作的就不是非常好,因为 Windows 是一个不区分大小写的系统。

    在 Windows 平台上,我们无法确定一个叫做 ECHO.py 的文件导入为模块是 echo 还是 Echo,或者是 ECHO。

    为了解决这个问题,我们只需要提供一个精确包的索引。

    (1)关于 __all__ 变量

    导入语句遵循如下规则:如果包定义文件 __init__.py 存在一个叫做 __all__ 的列表变量,那么在使用 from package import * 的时候就把这个列表中的所有名字作为包内容导入。

    作为包的作者,可别忘了在更新包之后保证 __all__ 也更新了啊。

    以下实例在 file:sounds/effects/__init__.py 中包含如下代码:

    __all__ = ["echo", "surround", "reverse"]
    

    这表示当你使用from sound.effects import *这种用法时,你只会导入包里面这三个子模块。

    如果 __all__ 真的没有定义,那么使用from sound.effects import *这种语法的时候,就不会导入包 sound.effects 里的任何子模块。他只是把包sound.effects和它里面定义的所有内容导入进来(可能运行__init__.py里定义的初始化代码)。

    这会把 init.py 里面定义的所有名字导入进来。并且他不会破坏掉我们在这句话之前导入的所有明确指定的模块。看下这部分代码:

    import sound.effects.echo
    import sound.effects.surround
    from sound.effects import *
    

    这个例子中,在执行 from...import 前,包 sound.effects 中的 echo 和 surround 模块都被导入到当前的命名空间中了。(当然如果定义了 __all__ 就更没问题了)

    通常我们并不主张使用 * 这种方法来导入模块,因为这种方法经常会导致代码的可读性降低。不过这样倒的确是可以省去不少敲键的功夫,而且一些模块都设计成了只能通过特定的方法导入。

    (2)推荐做法

    记住,使用 from Package import specific_submodule 这种方法永远不会有错。事实上,这也是推荐的方法。除非是你要导入的子模块有可能和其他包的子模块重名。

    如果在结构中包是一个子包(比如这个例子中对于包sound来说),而你又想导入兄弟包(同级别的包)你就得使用导入绝对的路径来导入。比如,如果模块sound.filters.vocoder 要使用包 sound.effects 中的模块 echo,你就要写成 from sound.effects import echo

    from . import echo
    from .. import formats
    from ..filters import equalizer
    

    无论是隐式的还是显式的相对导入都是从当前模块开始的。主模块的名字永远是"__main__",一个Python应用程序的主模块,应当总是使用绝对路径引用。

    包还提供一个额外的属性__path__。这是一个目录列表,里面每一个包含的目录都有为这个包服务的__init__.py,你得在其他__init__.py被执行前定义哦。可以修改这个变量,用来影响包含在包里面的模块和子包。

    这个功能并不常用,一般用来扩展包里面的模块。

    六、打包python程序成exe文件

    1.打包单个文件

    (1)安装PyInstaller:

    你可以通过pip来安装PyInstaller,如果还没有安装的话:

    pip install pyinstaller
    
    (2)打包你的程序:

    使用以下命令来打包你的Python脚本。–onefile选项用于创建单个可执行文件。

    pyinstaller --onefile your_script.py
    

    这将在dist目录下生成一个单独的.exe文件,你可以将这个文件分发给用户。

    2.和配置文件一起打包

    有时候程序文件有配置文件,需要一起打包

    [smtp]
    server = smtp.example.com
    port = 587
    username = your_email@example.com
    password = your_password
    from_addr = monitor@example.com
    to_addrs = admin1@example.com;admin2@example.com
    
    (1)安装依赖
    pip install pyinstaller configparser
    
    (2)创建打包规范文件(monitor.spec)
    # -*- mode: python -*-
    
    block_cipher = None
    
    a = Analysis(['monitor_tool.py'],
                 pathex=[],
                 binaries=[],
                 datas=[('config.ini', '.'), ('ips.txt', '.')],
                 hiddenimports=[],
                 hookspath=[],
                 runtime_hooks=[],
                 excludes=[],
                 win_no_prefer_redirects=False,
                 win_private_assemblies=False,
                 cipher=block_cipher,
                 noarchive=False)
    pyz = PYZ(a.pure, a.zipped_data,
                 cipher=block_cipher)
    exe = EXE(pyz,
              a.scripts,
              [],
              exclude_binaries=True,
              name='NetworkMonitor',
              debug=False,
              bootloader_ignore_signals=False,
              strip=False,
              upx=True,
              console=False )
    coll = COLLECT(exe,
                   a.binaries,
                   a.zipfiles,
                   a.datas,
                   strip=False,
                   upx=True,
                   name='NetworkMonitor')
    

    注意:生产环境使用时建议将console=False改为True以便查看运行状态

    (3)执行打包命令
    pyinstaller monitor.spec
    

    作者:晓风残月淡

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python项目工程文件组织结构指南

    发表回复