当前位置: 首页 > news >正文

Python程序打包指南:手把手教你一步步完成

最近感兴趣想将开发的项目转成Package,研究了一下相关文章,并且自己跑通了,走了一下弯路,这里记录一下如何打包一个简单的Python项目,展示如何添加必要的文件和结构来创建包,如何构建包,以及如何将其上传到Python包索引(PyPI)。

首先要确保安装最新版本:

# Unix/macOS
python3-m pip install--upgrade pip# windows
py-m pip install--upgrade pip

一个简单的项目

本教程使用一个名为example_package_YOUR_USERNAME_HERE的简单项目。如果你的用户名是me,那么包将会是example_package_me;另外确保有一个唯一的包名,不会与遵循本教程的其他人上传的包冲突。建议在打包自己的项目之前,按照本教程的原样使用这个项目。

在本地创建以下文件结构:

packaging_tutorial/
└── src/└── example_package_YOUR_USERNAME_HERE/├── __init__.py└── example.py

包含Python文件的目录应该与项目名称匹配。这简化了配置,对于安装包的用户来说更加明显。

__init__. py是将目录导入为包所必需的,即使在本教程中,该文件是空的。

example.py是包内模块的示例,该模块可能包含包的逻辑(函数、类、常量等)。打开该文件并输入以下内容:

def add_one(number):return number + 1

创建此结构后,需要在packaging_tutorial目录中运行本教程中的所有命令。

创建包文件

现在将添加用于准备项目以进行分发的文件。完成后,项目结构将如下所示:

packaging_tutorial/
├── LICENSE
├── pyproject.toml
├── README.md
├── src/
│   └── example_package_YOUR_USERNAME_HERE/
│       ├── __init__.py
│       └── example.py
└── tests/

创建测试目录

test/是测试文件的占位符,这里暂时将其留空。

选择构建后端

像pip和build这样的工具实际上不会将源代码转换为分发包(如轮子);该工作由构建后端执行。构建后端决定您的项目将如何指定其配置,包括元数据(有关项目的信息,例如,PyPI上显示的名称和标签)和输入文件。构建后端具有不同级别的功能,例如它们是否支持构建扩展模块,应该选择适合需求和偏好的一个。

这里可以从许多后端中进行选择;本教程默认使用Hatchling,但它将与支持元数据的setuptools、Flight、PDM和其他支持[project]表的方法相同。

pyproject.toml告诉构建前端工具,如pip和build,为项目使用哪个后端。以下是一些常见构建后端的示例,但请查看后端自己的留档以获取更多详细信息。

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"[build-system]
requires = ["flit_core>=3.4"]
build-backend = "flit_core.buildapi"[build-system]
requires = ["pdm-backend"]
build-backend = "pdm.backend"

requires键是构建包所需的包列表。前端应该在构建包时自动安装它们。前端通常在隔离的环境中运行构建,因此在这里省略依赖项可能会导致构建时错误。这应该始终包括后端的包,并且可能有其他构建时依赖项。

build-backend键是前端用来执行构建的Python对象的名称。

这两个值都将由构建后端的留档提供,或者由其命令行界面生成,不需要自定义这些设置。

构建工具的其他配置将在pyproject.toml工具部分或构建工具定义的特殊文件中。例如,当使用setuptools作为构建后端时,可以将其他配置添加到setup.pysettings.cfg文件,并指定setuptools。build_meta在构建中允许工具自动定位和使用这些。

配置元数据

打开pyproject.toml并输入以下内容。更改name以包含用户名;这可确保拥有唯一的包名,不会与遵循本教程的其他人上传的包冲突。

[project]
name = "example_package_YOUR_USERNAME_HERE"
version = "0.0.1"
authors = [{ name="Example Author", email="author@example.com" },
]
description = "A small example package"
readme = "README.md"
requires-python = ">=3.7"
classifiers = ["Programming Language :: Python :: 3","License :: OSI Approved :: MIT License","Operating System :: OS Independent",
][project.urls]
"Homepage" = "https://github.com/pypa/sampleproject"
"Bug Tracker" = "https://github.com/pypa/sampleproject/issues"
  • name是包的分发名称。它可以是任何名称,只要它只包含字母、数字、._-。它也不能已经在PyPI上使用。在本教程中,请务必使用自己的用户名更新它,因为这可以确保不会尝试上传与已存在的名称相同的包。
  • version是包版本。有关版本的更多详细信息,请参阅版本说明符规范。一些构建后端允许以其他方式指定它,例如从文件或git tag。
  • authors用于标识包的作者;可以为每个作者指定姓名和电子邮件。还可以以相同的格式列出maintainers
  • description是对包装的简短的一句话总结。
  • readme是包含包的详细描述的文件的路径。这显示在PyPI上的包详细信息页面上。在这种情况下,描述是从README.md加载的(这是一种常见的模式)。项目元数据规范中还有一种更高级的表格形式。
  • requires-python提供项目支持的Python版本。像pip这样的安装程序会回顾旧版本的包,直到找到一个具有匹配Python版本的包。
  • classifiers提供有关包的索引和pip一些附加元数据。在这种情况下,包仅与Python3兼容,根据MIT许可证获得许可,并且OS独立。您应该始终至少包括包适用于Python的哪个版本,包在哪个许可证下可用,以及包将适用于哪些操作系统。有关分类器的完整列表,请参阅https://pypi.org/classifiers/。
  • URL允许列出要在PyPI上显示的任意数量的额外链接。通常这可能是指向源、留档、问题跟踪器等。

有关可以在[project]表中定义的这些和其他字段的详细信息,请参阅项目元数据规范。其他常见字段是提高可发现性的关键字和安装包所需的依赖项

创建README.md

打开README.md并输入以下内容,也可以自定义此内容。

# Example PackageThis is a simple example package. You can use
[GitHub-flavored Markdown](https://guides.github.com/features/mastering-markdown/)
to write your content.

创建LICENSE

上传到Python包索引的每个软件包都必须包含许可证。这将告诉安装软件包的用户他们可以使用上传软件包的条款。有关选择许可证的帮助,请参阅https://choosealicense.com/。选择许可证后,打开`LICENSE`并输入许可证文本。例如,如果选择了MIT许可证:

Copyright (c) 2018 The Python Packaging AuthorityPermission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

大多数构建后端会自动在包中包含许可证文件。有关详细信息,请参阅后端的留档。

包括其他文件

上面列出的文件将自动包含在源发行版中。如果想包含其他文件,请参阅构建后端的留档。

生成分发档案

下一步是为包生成分发包。这些是上传到Python包索引的存档,可以通过pip安装。确保安装了最新版本的PyPA bulid:

# Unix/macOS
python3 -m pip install --upgrade build# Windows
py -m pip install --upgrade build

现在从pyproject. toml所在的同一目录运行下面的命令:

# Unix/macOS
python3 -m build# Windows
py -m build

这个命令应该输出很多文本,一旦完成应该在dist目录中生成两个文件:

dist/
├── example_package_YOUR_USERNAME_HERE-0.0.1-py3-none-any.whl
└── example_package_YOUR_USERNAME_HERE-0.0.1.tar.gz

tar.gz文件是源发行版,而.whl文件是构建发行版。较新的pip版本优先安装构建发行版,但如果需要可以回退到源发行版。应该始终上传源发行版,并为项目兼容的平台提供构建发行版。在这种情况下,本文的示例包与任何平台上的Python兼容,因此只需要一个构建发行版。

上传分发档案

最后将打好的包上传到Python包索引,可供其它人安装。需要做的第一件事是在TestPyPI上注册一个帐户,这是一个用于测试和实验的包索引的单独实例。对于像本教程这样不一定想上传到真实索引的东西,这样的测试环境是非常好的。

首先要注册一个帐户,打开https://test.pypi.org/account/register/并完成该页面上的步骤。还需要在能够上传任何包之前验证填写的电子邮件地址。有关更多详细信息,请参阅[使用TestPyPI](https://packaging.python.org/en/latest/guides/using-testpypi/)。

要安全地上传项目,还需要一个PyPIAPI令牌。https://test.pypi.org/manage/account/#api-tokens创建一个,将“范围”设置为“整个帐户”。**在复制并保存令牌之前不要关闭页面——您将不会再看到该令牌。**

这一步需要QR扫描二维码,得到6位数字验证码,另外获得的令牌如何使用呢?这是踩的弯路,详细说一下:

PyPi 调整了安全策略,不再允许启用两步验证的账号使用用户名密码来上传项目了,必须使用 API 令牌来进行身份验证。登录 PyPi ,进入账户设置页,点击「添加 API 令牌」按钮创建 API 令牌。然后修改 ~/.pypirc 配置文件, 用户名字段改为 __token__ ,密码字段改为刚才创建的令牌:

[testpypi]username = __token__password = pypi-AgENdGVzdC5weXBpLm9xxxxxxxxxxxxxxx

注册好之后就可以使用twine上传分发包。上传之前需要先安装Twine:

# Unix/macOS
python3 -m pip install --upgrade twine# Windows
py -m pip install --upgrade twine

安装后,运行Twine上传dist下的所有存档:

# Unix/macOS
python3 -m twine upload --repository testpypi dist/*# Windows
py -m twine upload --repository testpypi dist/*

命令完成后,您应该会看到类似于以下内容的输出:

Uploading distributions to https://test.pypi.org/legacy/
Enter your username: __token__
Uploading example_package_YOUR_USERNAME_HERE-0.0.1-py3-none-any.whl
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 8.2/8.2 kB • 00:01 • ?
Uploading example_package_YOUR_USERNAME_HERE-0.0.1.tar.gz
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.8/6.8 kB • 00:00 • ?

上传后,打的包应该可以在TestPyPI上查看;例如:https://test.pypi.org/project/example_package_YOUR_USERNAME_HERE

在这里插入图片描述

安装新上传的包

上传成果后,可以使用pip安装包并验证它是否有效。创建一个虚拟环境并从TestPyPI安装上传的包:

# Unix/macOS
python3 -m pip install --index-url https://test.pypi.org/simple/ --no-deps example-package-YOUR-USERNAME-HERE# Windows
py -m pip install --index-url https://test.pypi.org/simple/ --no-deps example-package-YOUR-USERNAME-HERE

pip应该从TestPyPI安装包,输出应该如下所示:

Collecting example-package-YOUR-USERNAME-HEREDownloading https://test-files.pythonhosted.org/packages/.../example_package_YOUR_USERNAME_HERE_0.0.1-py3-none-any.whl
Installing collected packages: example_package_YOUR_USERNAME_HERE
Successfully installed example_package_YOUR_USERNAME_HERE-0.0.1

注 此示例使用--index-url标志来指定TestPyPI而不是live PyPI。此外,它还指定--no-deps。由于TestPyPI没有与live PyPI相同的软件包,因此尝试安装依赖项可能会失败或安装意外的东西。虽然我们的示例包没有任何依赖项,但在使用TestPyPI时避免安装依赖项是一个很好的做法。

接下来就可以通过导入软件包来测试它是否已正确安装。确保仍在虚拟环境中,然后运行Python:

from example_package_YOUR_USERNAME_HERE import exampleexample.add_one(2)
# 3

后续

恭喜,已成果打包并分发了一个Python项目!

请记住,本教程展示了如何将包上传到Test PyPI,这不是永久存储。Test系统偶尔会删除包和帐户。最好像本教程一样使用TestPyPI进行测试和实验。

当准备好将真实包上传到Python包索引时,可以像本教程中一样执行相同的操作,但有以下重要区别:

  • 为包选择一个难忘且独特的名称;
  • 在https://pypi.org上注册一个帐户,这是两个独立的服务器,测试服务器的登录详细信息不与主服务器共享;
  • 使用twine上传dist/*上传自己的包,并输入正式PyPI环境上注册的帐户的凭据。在生产环境中上传包,不需要指定--repository;默认情况下,包将上传到https://pypi.org/;
  • 使用python3-m pip install[your-package]从真正的PyPI安装包;

参考

  • Hattch

  • Flit

  • pdm

  • poetry

  • PEP517

  • PEP518

  • https://segmentfault.com/a/1190000008663126

  • Packaging binary extensions]

  • https://www.fournoas.com/posts/authentication-on-pypi-using-api-token-instead-of-password/

  • https://packaging.python.org/en/latest/tutorials/packaging-projects/

相关文章:

Python程序打包指南:手把手教你一步步完成

最近感兴趣想将开发的项目转成Package,研究了一下相关文章,并且自己跑通了,走了一下弯路,这里记录一下如何打包一个简单的Python项目,展示如何添加必要的文件和结构来创建包,如何构建包,以及如何…...

Linux yum 使用时提示 获取 GPG 密钥失败Couldn‘t open file RPM-GPG-KEY-EPEL-7

资料 错误提示: no crontab for root - using an empty one 888 原因剖析: 第一次使用crontab -e 命令时会让我们选择编辑器,很多人会不小心选择默认的nano(不好用),或则提示no crontab for root - usin…...

OpenGL_Learn13(材质)

1. 材质 cube.vs #version 330 core layout (location 0) in vec3 aPos; layout (location 0 ) in vec3 aNormal;out vec3 FragPos; out vec3 Normal;uniform mat4 model; uniform mat4 view; uniform mat4 projection;void main() {FragPosvec3(model*vec4(aPos,1.0));Norma…...

buildadmin+tp8表格操作(1)----表头上方添加按钮和自定义按钮

buildAdmin 的表头上添加一些按钮&#xff0c;并实现功能 添加按钮 <template><!-- buttons 属性定义了 TableHeader 本身支持的顶部按钮&#xff0c;仅需传递按钮名即可 --><!-- 这里的框架自带的 顶部按钮 分别有 刷新 &#xff0c; 添加&#xff0c; 编辑&…...

MySQL 定时计划任务 事件的使用

目录 查看事件是否开启 开启事件 1&#xff09;通过设置全局参数修改 2&#xff09;更改配置文件 MySQL如何创建并执行事件&#xff1f; 例 1 MySQL查看事件状态信息 MySQL修改和删除事件 例 1 例 2 删除事件 例 3 在数据库管理中&#xff0c;经常要周期性的执行某…...

C++构造函数 拷贝构造函数 括号法显示法隐式转换法实现类

一.无参构造 & 有参构造 & 拷贝构造函数 拷贝的是自己所属的类&#xff0c;也就是克隆自己。 所以传参要穿自己的类名。 克隆归克隆&#xff0c;但是不能把本身给改了&#xff0c;所以参数前要加const。class Person { public:int age;public:Person(){cout<<&q…...

FreeRTOS中的内存分配策略

FreeRTOS为内存管理提供了几种不同的策略&#xff0c;分别由heap_1.c至heap_5.c实现。以下是每种策略&#xff1a; heap_1.c: 最简单的策略。只允许一次性的内存分配。不允许内存释放。对于只分配内存但不释放的系统特别有用&#xff0c;如仅在启动时分配任务和队列的系统。内存…...

HP惠普光影精灵7笔记本Victus by HP 16.1英寸游戏本16-d0000原装出厂Windows11.21H2预装OEM系统

下载链接&#xff1a;https://pan.baidu.com/s/1LGNeQR1AF1XBJb5kfZca5w?pwdhwk6 提取码&#xff1a;hwk6 可适用的型号&#xff1a; 16-d0111tx&#xff0c;16-d0112tx&#xff0c;16-d0125tx&#xff0c;16-d0127tx&#xff0c;16-d0128tx&#xff0c;16-d0129tx&#…...

组合模式 rust和java的实现

文章目录 组合模式介绍实现javarsut 组合模式 组合模式&#xff08;Composite Pattern&#xff09;&#xff0c;又叫部分整体模式&#xff0c;是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象&#xff0c;用来表示部分以及整体层次。这种类型的设计…...

大数据基础设施搭建 - MySQL

文章目录 一、检查是否安装过MySQL二、上传安装包三、安装MySQL3.1 安装mysql依赖3.2 安装mysql-client3.3 安装mysql-server 四、启动MySQL五、配置MySQL5.1 修改密码&#xff08;1&#xff09;查看密码&#xff08;2&#xff09;登陆&#xff08;3&#xff09;设置复杂密码&a…...

二叉树递归遍历

能帮到你的话&#xff0c;就给个赞吧 &#x1f618; 二叉树遍历算法 指遍历一遍二叉树就能得到答案 什么是二叉树遍历 二叉树遍历 前中后序遍历 递归遍历 3种时间节点 递归遍历会依次遍历到每个节点。 而前中后序则是在递归遍历的基础上选择操作发生的时间。 递归遍历 …...

【ArcGIS Pro二次开发】:CC工具箱1.1.1更新_免费_安装即可用

CC工具箱1.1.1更新【2023.11.15】 使用环境要求&#xff1a;ArcGIS Pro 3.0 一、下载链接 工具安装文件及使用文档&#xff1a; https://pan.baidu.com/s/1OJmO6IPtMfX_vob3bMtvEg?pwduh5rhttps://pan.baidu.com/s/1OJmO6IPtMfX_vob3bMtvEg?pwduh5r 二、使用方法 1、在下…...

Dubbo的优雅下线原理分析

文/朱季谦 Dubbo如何实现优雅下线&#xff1f; 这个问题困扰了我一阵&#xff0c;既然有优雅下线这种说法&#xff0c;那么&#xff0c;是否有非优雅下线的说法呢&#xff1f; 这&#xff0c;还真有。 可以从linux进程关闭说起&#xff0c;其实&#xff0c;我们经常使用到杀…...

leetcode做题笔记2342. 数位和相等数对的最大和

给你一个下标从 0 开始的数组 nums &#xff0c;数组中的元素都是 正 整数。请你选出两个下标 i 和 j&#xff08;i ! j&#xff09;&#xff0c;且 nums[i] 的数位和 与 nums[j] 的数位和相等。 请你找出所有满足条件的下标 i 和 j &#xff0c;找出并返回 nums[i] nums[j]…...

c# YOLOV5目标检测部署

using Emgu.CV; using Emgu.CV.CvEnum; using Emgu.CV.Dnn; using Emgu.CV.Structure; using Emgu.CV.Util...

学习笔记6——垃圾回收

学习笔记系列开头惯例发布一些寻亲消息 链接&#xff1a;https://baobeihuijia.com/bbhj/contents/3/190801.html java垃圾回收&#xff08;stop the world&#xff09; 专注于堆和方法区的垃圾回收&#xff0c;年轻代&#xff0c;老年代&#xff0c;永久代判断对象是否还存…...

3.1 Windows驱动开发:内核远程堆分配与销毁

在开始学习内核内存读写篇之前&#xff0c;我们先来实现一个简单的内存分配销毁堆的功能&#xff0c;在内核空间内用户依然可以动态的申请与销毁一段可控的堆空间&#xff0c;一般而言内核中提供了ZwAllocateVirtualMemory这个函数用于专门分配虚拟空间&#xff0c;而与之相对应…...

C++: 模板初阶

文章目录 一. 泛型编程二. 函数模板函数模板的原理函数模板的实例化隐式实例化: 让编译器根据实参推演模板参数的实际类型显示实例化: 在函数名后的<>中制定模板参数的世纪类型 模板参数的匹配原则 三. 类模板类模板的定义格式类模板的实例化 一. 泛型编程 如何实现一个…...

人工智能基础_机器学习036_多项式回归升维实战3_使用线性回归模型_对天猫双十一销量数据进行预测_拟合---人工智能工作笔记0076

首先我们拿到双十一从2009年到2018年的数据 可以看到上面是代码,我们自己去写一下 首先导包,和准备数据 from sklearn.linear_model import SGDRegressor import numpy as np import matplotlib.pyplot as plt X=np.arange(2009.2020)#左闭右开,2009到2019 获取从2009到202…...

【算法挨揍日记】day29——139. 单词拆分、467. 环绕字符串中唯一的子字符串

139. 单词拆分 139. 单词拆分 题目描述&#xff1a; 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。 注意&#xff1a;不要求字典中出现的单词全部都使用&#xff0c;并且字典中的单词可以重复使用。 解题思路&am…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...

免费数学几何作图web平台

光锐软件免费数学工具&#xff0c;maths,数学制图&#xff0c;数学作图&#xff0c;几何作图&#xff0c;几何&#xff0c;AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...

C# 表达式和运算符(求值顺序)

求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如&#xff0c;已知表达式3*52&#xff0c;依照子表达式的求值顺序&#xff0c;有两种可能的结果&#xff0c;如图9-3所示。 如果乘法先执行&#xff0c;结果是17。如果5…...

毫米波雷达基础理论(3D+4D)

3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文&#xff1a; 一文入门汽车毫米波雷达基本原理 &#xff1a;https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...