Python基础

前言

python 是一种以 “更好写、更好读、适合日常工程工作 ”被开发出来的语言。它目标不是“性能最强”,而是:

  • 语法清晰,代码像人能读懂的话
  • 写得快,改得快
  • 适合脚本、工具、系统管理、原型开发
  • 既简单,又不是玩具
  • 能和 C 等底层语言配合

这也是为什么 Python 后来会特别适合:

  • 自动化脚本
  • 运维工具
  • Web 开发
  • 数据分析
  • AI / 机器学习

因为它的出发点本来就是“让人高效完成工作”。

Python的发展历史

Python 从发展至今,已经有三个大版本的更新了,出于其目的可归结为

  • Python 1 回答的是:程序为什么非得这么难写?
  • Python 2 回答的是:这门语言能不能真的扛工程?
  • Python 3 回答的是:已经成功的语言,怎么修掉历史债务继续往前走?
Python 1:解决“写程序太费劲、太难读”的问题

Python 1 的思路非常明确:让语言优先服务“人写代码”的体验。它主要通过这些设计解决问题:

  • 用缩进表达代码块
    • 强制代码结构清晰
    • 减少花括号、begin/end 之类噪音
  • 语法尽量简单直白
    • 让代码更接近自然阅读
  • 内置高层数据结构
    • list、dict、字符串处理这些开箱可用
    • 不需要开发者自己从底层拼很多东西
  • 模块化机制
    • 代码可以拆文件、拆模块,不必全堆在一起
  • 异常机制
    • 错误处理比单纯返回错误码更清晰
  • 解释执行
    • 试验、修改、迭代很快

所以 Python 1 解决的核心,不是“性能问题”,而是: 把“写程序”从偏底层、偏啰嗦,拉到偏表达、偏效率。

Python 2:解决“好写还不够,还得能做大项目”的问题

Python 2 不是推翻 Python 1,而是在它基础上把“工程能力”补齐。它主要通过这些方向解决问题:

  • 增强语言表达力
    • 列表推导式、生成器、迭代器、装饰器等能力逐渐成熟
    • 让开发者能用更简洁、更抽象的方式写逻辑
  • 完善对象模型和标准库
    • 让 Web、文件、网络、文本、测试等常见需求更容易落地
  • 提升大型程序可组织性
    • 模块、包、类、异常体系更完整
  • 开始认真处理 Unicode
    • 虽然最后没彻底解决,但 Python 2 时代已经意识到国际化文本是核心问题
  • 形成生态
    • 这时 Python 才真正大规模进入生产环境

所以 Python 2 解决的核心是:让 Python 从“写脚本很舒服”,升级成“做真实业务也很能打”。 但 Python 2 也留下了一个重大副作用:它为了兼容历史,慢慢积累了不少设计包袱,尤其是字符串/编码、标准库一致性这些问题。

Python 3:解决“历史包袱太重,继续修补会越来越乱”的问题

问题
Python 2 很成功,但成功之后,老设计的问题被无限放大了。最核心的几个问题是:

  1. 文本和字节混乱
  2. 语言规则不够一致
  3. 历史兼容成本太高

Python 3 的解决方式很硬:宁可不兼容,也要把基础规则理顺。 主要是这样做的:

  • 彻底区分文本和二进制
    • str 表示文本
    • bytes 表示字节
    • 不再允许模糊混用
    • 这让编码、I/O、网络、文件处理逻辑更清晰
  • 统一语义
    • print 改成函数
    • / 改成真正除法,// 表示整除
    • range 统一成更现代的行为
    • map / filter / zip 更偏迭代器风格
  • 清理标准库
    • 调整一些模块命名和组织方式
    • 让整体结构更统一
  • 统一类模型
    • 去掉 Python 2 里旧式类 / 新式类的割裂
  • 为未来工具链和大型工程打基础
    • 更适合类型注解、异步编程、现代 packaging、跨平台文本处理

所以 Python 3 解决的核心是:把 Python 从“历史上很好用但内部不够整洁的语言”,变成“可以长期演进的现代语言”。

Python环境

一个普通 Python 应用怎么落地

  1. 用 uv / pyenv/ conda 选 Python版本建环境
  2. 用 venv 得到 .venv
  3. 用 pip 安装依赖
  4. 程序运行:python main.py
  5. 如果要把项目做成可安装包,再用 setuptools /build 构建, 产出 wheel 包文件

Python3的项目结构

Python 3 最小常规工程的项目结构

  py-test/                     # 项目根目录
  ├── pyproject.toml           # 项目配置,定义依赖、Python 版本、构建方式
  ├── README.md                # 项目说明文档
  ├── src/                     # 源码根目录
  │   └── py_test/             # 主 Python 包目录
  │       ├── __init__.py      # 包初始化文件
  │       └── main.py          # 项目主入口或核心启动文件
  └── tests/                   # 测试目录
      └── test_main.py         # 主入口或核心逻辑的基础测试

pyproject配置

pyproject.toml 拆成三种职责:

  1. 构建系统声明
  2. 项目元信息
  3. 工具配置(为1声明的构建工具提供配置)
##  如果没有这一段,pip install -e .、构建 wheel、editable install 这些行为就没有标准入口。
[build-system]
## 告诉安装工具,构建项目之前先准备 setuptools 和 wheel
requires = ["setuptools>=68", "wheel"]
## 告诉工具,真正负责把项目打包成可安装形式的是 setuptools.build_meta
build-backend = "setuptools.build_meta"

[project]

##  提供了项目元信, 定义这个项目“是谁”
name = "py-test"
version = "0.1.0"
description = "Reference Python 3 project structure with CLI, API, services, and tests"
readme = "README.md"
requires-python = ">=3.11"
authors = [{ name = "OpenAI Example" }]
license = { text = "MIT" }

## 定义这个项目“运行需要什么依赖”
dependencies = [
  "fastapi>=0.115,<1",
  "pydantic>=2.8,<3",
  "pydantic-settings>=2.4,<3",
  "uvicorn>=0.30,<1",
]

## 你自己定义的“可选依赖分组”
[project.optional-dependencies]
##  开发者可以通过 pip install -e ".[dev]" 一次性装齐开发环境
dev = [
  "httpx>=0.27,<1",
  "mypy>=1.11,<2",
  "pytest>=8,<9",
  "pytest-cov>=5,<6",
  "ruff>=0.6,<1",
]

## 测试环境
test =[
 "py-test[dev]" ## 可以这么引用dev依赖 
]

## 定义这个项目“安装后暴露什么命令”
[project.scripts]

# 生成一个命令:py-test
# 这个命令的目标函数是:
#      - 模块:py_test.cli
#      - 函数:main
# 原理: 也是 shebang
py-test = "py_test.cli:main"

## 源码包地址,给构建工具
[tool.setuptools.packages.find]
where = ["src"]

# 指定测试目录和默认参数
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "-q"
# 指定 Python 目标版本和 lint 规则
[tool.ruff]
target-version = "py311"
line-length = 100
[tool.ruff.lint]
select = ["B", "E", "F", "I", "UP"]
# 指定类型检查版本和检查范围
[tool.mypy]
python_version = "3.11"
strict = true
packages = ["py_test"]

pyproject.toml 是“现代做法”,但很多用户的第一反应仍然是:

pip install -r requirements.txt

其意思是让 pip install 去读取 requirements.txt 这个文件,把文件里的每一行都当成安装要求来处理

## requirements.txt
##   文件内容的核心是:
-e .[dev]

python模块

Python 模块命名空间的形式,采用"点模块名称"。

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

在导入一个包的时候,Python 会根据 sys.path 中的目录来寻找这个包中包含的子目录。
目录只有包含一个叫做 init.py 的文件才会被认作是一个包

sound/                          顶层包
      __init__.py               初始化 sound 包
      effects/                  声音效果子包
              __init__.py
              echo.py
              surround.py
              reverse.py

在运行文件中可以使用以下方式导入

## 导包
import sound.effects.echo
# 这将会导入子模块:sound.effects.echo。 他必须使用全名去访问:
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)

## 导入子模块的方法
from sound.effects import echo
## echo,并且他不需要那些冗长的前缀,所以他可以这样使用:
echo.echofilter(input, output, delay=0.7, atten=4)

## 直接导入一个函数或者变量:
from sound.effects.echo import echofilter
## 可以直接使用他的 echofilter() 函数:
echofilter(input, output, delay=0.7, atten=4)

## 找到这个包里面所有的子模块,然后一个一个的把它们都导入进来
from sound.effects import * 

## 如果包定义文件 __init__.py 存在一个叫做 __all__ 的列表变量,那么在使用 from package import * 的时候就把这个列表中的所有名字作为包内容导入。
## sounds/effects/__init__.py 中包含如下代码:
__all__ = ["echo", "surround", "reverse"]
按模块/包运行

Python 包可以通过 包名 的方式直接运

python -m py_test

当你用这方式时,Python 会去找:

 py_test/__main__.py
  • 如果找到了,就执行它。
  • 如果没有,通常就不能这样把整个包当可运行入口来启动。

这对开发阶段很方便,也更符合 Python 原生方式。

python的执行过程

Python 执行一个 .py 文件,核心流程可以概括成:

源码 .py -> 编译成字节码 -> 交给 Python 虚拟机执行 -> 可选地缓存成 .pyc

  1. 第一步:读取源码文件
    Python 解释器首先会做的不是直接“逐字符执行”,而是先把这个文件读进来。
  2. 第二步:词法分析和语法分析
    Python 读到源码后,会先做解析工作,大致包括:
    • 把字符流切成 token
    • 按语法规则分析结构
    • 检查语法是否正确
  3. 第三步:编译成字节码
    这里的“编译”不是指像 C 那样编译成机器码,而是编译成一种给 Python 虚拟机执行的中间指令。
  4. 第四步:交给 Python 虚拟机执行
    编译完字节码后,Python 并不会把它变成原生二进制,而是交给 Python 虚拟机 去执行。
  5. 第五步:把字节码缓存成 .pyc ,
    Python 通常会把编译结果缓存下来,写入:pycache/ 里面的 .pyc 文件
    这样下次再次导入同一个模块时,如果源码没变化,就可以直接使用缓存,不必重新编译。也可以使用以前命令提前编译
    python -m compileall -q src
    

从上面流程来看与JAVA的流程相似,

  • 共同点是:都不是直接执行源码,而是先转成字节码,再交给自己的虚拟机执行。
  • 不同是:Java 把字节码当正式产物来管理,Python 通常把字节码当内部缓存来使用。

为什么 Python 明明也有“编译”,但我们仍然把它叫解释型语言?

“解释型 / 编译型”这个分类,本来就不是看“有没有编译”,而是看程序最终是怎么被执行、编译阶段对用户是什么形态。 Python 之所以被叫解释型语言,不是因为它完全没有编译,而是因为它不会先生成独立机器码产物再运行,而是通常由解释器在运行时将源码编译为字节码并交给虚拟机执行。

Python虚拟机
维度Python虚拟机(CPython)JVM(Java HotSpot)关键区别
本体是什么Python 官方实现里的运行时核心Java 官方主流运行时CPython 是“语言实现的一部分”,JVM 是“语言平台核心”
输入源码.py.java都先从源码开始
中间产物Python 字节码,常见缓存为 .pycJVM 字节码,文件是 .class两边都有字节码
字节码标准化程度偏实现内部细节,主要跟着 CPython 版本走高度标准化,JVM 规范明确JVM 的字节码规范更稳定、更统一
执行核心字节码解释器逐条执行解释执行 + JIT 编译JVM 会把热点代码编译成机器码,CPython 默认不会
JIT默认没有成熟生产级 JIT有成熟 HotSpot JIT(C1/C2)这是性能差异的核心来源之一
热点优化很有限很强,支持内联、逃逸分析、锁消除等JVM 更擅长长期运行后的性能爬升
内存管理引用计数 + 循环GCTracing GC,分代回收、多种收集器CPython 更简单直接,JVM 更复杂但更强
对象管理成本动态对象开销大,属性查找和调用成本高类型信息更稳定,更利于优化Python 的动态性更灵活,也更贵
类型系统动态类型静态类型JVM 更容易做激进优化
函数/方法调用运行时动态分派更多调用路径更可预测Java 方法调用更容易被 JIT 内联
线程模型有原生线程,但有 GIL原生线程,无 GILCPU 密集多线程时,Java 更容易吃满多核
多核并行多进程更常见多线程并行更自然Python 想并行常靠进程池或底层库
启动速度通常较快通常较慢一点JVM 需要类加载、JIT 预热等
预热特性基本无“越跑越快”这一套明显有 warm-up,越跑越容易快长跑服务通常 JVM 更占优
纯CPU计算通常较慢通常较快同样算法,Java 往往快很多
I/O 场景表现可以很好也很好I/O 场景差距没纯计算那么大
本地扩展大量依赖 C/C++ 扩展提速JNI 也能调本地库Python 常把重活下沉给 numpy、pandas、torch
打包后运行常见是源码 + 环境运行常见是 jar 跑在 JVM 上Python 更偏脚本/环境驱动,Java 更偏平台/制品驱动
兼容性边界很多库默认优先支持 CPythonJava 生态天然围绕 JVMPython 生态“解释器差异”更值得关注
典型代表命令python app.pyjava -jar app.jar使用方式也反映平台差异

语法笔记

记录属于python特有的语法笔记内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值