跳转至

2026 年

Python 项目结构与打包完全指南:从入门到实践

当你完成一个 Python 项目,想要发布到 PyPI 供全球开发者下载时,你是否遇到过这些困惑:

  • pip install 背后到底发生了什么?
  • 为什么安装 beautifulsoup4 却要 import bs4
  • 项目代码应该放在根目录还是 src 目录?
  • python -m builduv build 有什么区别?

本文将从依赖安装的底层机制出发,逐步深入到 WHL 文件构建流程,最后探讨现代化项目结构的最佳实践。无论你是刚接触 Python 打包的新手,还是希望迁移到现代工具链的开发者,这篇文章都能给你清晰的指引。

依赖安装机制:当你执行 pip install 时发生了什么?

软件包从哪来?——PyPI 与 WHL 文件

当你执行 pip install flask 时,工具背后做了三件核心的事:

  1. 查询元数据:向 PyPI(Python Package Index,Python 官方的软件包仓库)请求 flask 的包信息
  2. 下载 WHL 文件:根据你的 Python 版本和操作系统,选择最合适的 .whl 文件下载
  3. 解压安装:将 WHL 文件解压到当前 Python 环境的 site-packages 目录

WHL(Wheel) 是 Python 的二进制分发格式标准(由 PEP 427 定义)。它本质上就是一个 ZIP 压缩包,里面包含了:

  • 预编译的代码(或纯 Python 源代码)
  • 包的元数据(依赖关系、版本信息等)

让我们以 Flask 3.1.1 为例,看看 WHL 文件的真面目:

# 下载 Flask 的 WHL 文件(不安装)
pip download flask==3.1.1 -d ./downloads

# 查看 WHL 内容(WHL 就是 ZIP)
unzip -l ./downloads/flask-3.1.1-py3-none-any.whl

马修·伯恩斯坦讲线性代数系列:矩阵的介绍

原文:Introducing matrices

在这里,我将介绍思考矩阵的三种主要方法。当我在本科线性代数课程中第一次接触到矩阵时,这种对矩阵多方面思考方式的高级描述将帮助我更好地直觉矩阵。

引言

矩阵是线性代数中的基本概念,在科学和工程领域中无处不在。从表面上看,矩阵只是一个二维的值数组。例如,以下是一个矩阵:

\[\begin{bmatrix}1 & -2 & 0 \\ 4 & -3 & 1 \\ 0 & 6 & -2 \end{bmatrix}\]

正如我在上一篇博客文章中讨论的那样,有些概念需要从多个角度观察才能掌握其真实本质。尽管矩阵表面上很简单,但我认为矩阵是其中一个概念,并且我相信,如果一开始就提供对矩阵的高层次、多视角概述,以便为未来的线性代数学习提供背景,那么对于我--大学线性代数课程的二年级学生来说,这会对我有所帮助。在这篇文章中,我将介绍查看矩阵的三个主要角度,这对我以前的自己有帮助。

预备知识

在介绍观察矩阵的三种角度之前,我将介绍一些符号。首先,一个矩阵是一个矩形的值数组。例如,以下矩阵 \(\boldsymbol{A}\)\(m\) 行和 \(n\) 列:

\[\boldsymbol{A} := \begin{bmatrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & \ddots & \vdots \\ a_{m,1} & a_{m,2} & \dots & a_{m,n} \end{bmatrix}\]

马修·伯恩斯坦讲线性代数系列:开篇

马修·伯恩斯(Matthew N. Bernstein) 是计算生物学与机器学习领域的研究者,现任 Cellular Intelligence 首席计算科学家。

他于2019年获威斯康星大学麦迪逊分校计算机科学博士学位,本科毕业于圣母大学。此前曾在 Stellaromics 和 Immunitas Therapeutics 担任机器学习与计算生物学科学家,并在 Morgridge Institute 从事博士后研究。Bernstein 专注于将高维基因组学数据转化为可指导人类健康研究的洞见,在空间转录组学、药物靶点识别和深度学习模型开发方面有丰富经验。

他在技术博客中,撰写了大量关于线性代数、变分自编码器、信息论基础等数学与机器学习概念的科普文章,以清晰的数学解释和直观的可视化著称。本系列是从马修的技术博客中筛选出有关线性代数的文章进行翻译后组成的一个合集。

马修·伯恩斯坦讲线性代数系列目录如下:

Golang源码分析系列之Map底层实现

映射也被称为哈希表(hash table)、字典。它是一种由key-value组成的抽象数据结构。大多数情况下,它都能在O(1)的时间复杂度下实现增删改查功能。若在极端情况下出现所有key都发生哈希碰撞时则退回成链表形式,此时复杂度为O(N)。

映射底层一般都是由数组组成,该数组每个元素称为桶,它使用hash函数将key分配到不同桶中,若出现碰撞冲突时候,则采用链地址法(也称为拉链法)或者开放寻址法解决冲突。下图就是一个由姓名-号码构成的哈希表的结构图:

Go语言中映射中key若出现冲突碰撞时候,则采用链地址法解决,Go语言中映射具有以下特点:

  • 引用类型变量
  • 读写并发不安全
  • 遍历结果是随机的

数据结构

Go语言中映射的数据结构是runtime.hmap(runtime/map.go):

// A header for a Go map.
type hmap struct {
    count     int //  元素个数,用于len函数返回map元素数量
    flags     uint8 // 标志位,标志当前map正在写等状态
    B         uint8  // buckets个数的对数,即桶数量 = 2 ^ B
    noverflow uint16 // overflow桶数量的近似值,overflow桶即溢出桶,即链表法中存在链表上的桶的个数
    hash0     uint32 // 随机数种子,用于计算key的哈希值

    buckets    unsafe.Pointer // 指向buckets数组,如果元素个数为0时,该值为nil
    oldbuckets unsafe.Pointer // 扩容时指向旧的buckets
    nevacuate  uintptr        // 用于指示迁移进度,小于此值的桶已经迁移完成

    extra *mapextra // 额外记录overflow桶信息
}

pkg-config快速入门指南

pkg-config 是一个帮助开发人员在编译和链接程序时发现和使用库的辅助工具。它提供了一种方法来获取库的编译和链接参数,使得在编译时链接库变得更加容易和一致。pkg-config 通常用于Unix-like系统,并且支持多种编程语言。

pkg-config 的工作原理是查询一个名为.pc的文件,这些文件包含了关于库的元数据,例如库的安装位置、编译器标志、链接器标志等。当你安装一个库时,通常会在/usr/lib/pkgconfig/usr/share/pkgconfig目录下安装相应的.pc文件。

如何使用 pkg-config

查询库的编译和链接标志

使用pkg-config查询库的编译和链接标志是最常见的用途。例如,如果你想使用libopus库,你可以使用以下命令来获取编译和链接标志:

pkg-config --cflags --libs opus

这个命令会输出类似以下内容:

-I/usr/include/opus -lopus

这些标志可以直接在编译命令中使用。