Java开发者转战Python:基础篇
  # 一、Python简介与环境搭建
# 1、Python的发展历程与特点
作为Java开发者,你可能听过这样一个段子:"人生苦短,我用Python"。这不仅仅是一句口号,而是Python简洁高效的真实写照。
# 1.1、Python的历史演进
Python由Guido van Rossum在1989年圣诞节期间创造,初衷是开发一门既简单又强大的编程语言。让我们快速了解它的演进历程:
- Python 1.0(1994年):确立了核心设计理念,引入lambda、map、filter等函数式编程特性
 - Python 2.x(2000-2010年):逐渐流行,成为科学计算和Web开发的重要工具。最后版本是Python 2.7(2010年)
 - Python 3.x(2008年至今):彻底重新设计,修正了许多历史遗留问题,但不向后兼容Python 2
 
需要注意的是,Python 2已经在2020年1月1日正式停止维护。如果你是现在开始学习Python,直接学Python 3就好,完全不用纠结Python 2。
# 1.2、3的重大改进
作为Java开发者,你会欣赏Python 3带来的这些改进:
- 统一的Unicode字符串处理:所有字符串默认Unicode,告别Java早期的字符编码噩梦
 - 更清晰的整数除法:
3/2得到1.5而不是1,整除使用//操作符 - 改进的异常语法:类似Java的
catch语法,except Exception as e更直观 - 类型注解支持(Python 3.5+):让习惯静态类型的Java开发者更舒适
 - 异步编程原生支持(Python 3.5+):
async/await语法,类似Java的CompletableFuture 
# 1.3、Python的设计哲学
在Python交互环境中输入import this,你会看到"The Zen of Python"(Python之禅)。这是Python的设计理念,其中几条特别值得Java开发者关注:
优美胜于丑陋(Beautiful is better than ugly)
明了胜于晦涩(Explicit is better than implicit)
简洁胜于复杂(Simple is better than complex)
可读性很重要(Readability counts)
对比Java冗长的样板代码,Python追求的是用最少的代码表达最清晰的意图。比如创建一个Person类:
// Java写法
public class Person {
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }
}
# Python写法(使用dataclass)
from dataclasses import dataclass
@dataclass
class Person:
    name: str
    age: int
看到差距了吧?Python只用4行代码就实现了Java需要20多行完成的功能。
# 1.4、Python的核心优势
简洁易读的语法:用缩进代替花括号,代码结构一目了然。习惯了Java的你可能一开始不适应,但很快就会爱上这种清爽的感觉
丰富的标准库和第三方生态:Python自带"电池"(batteries included),标准库几乎覆盖了日常开发的各个方面。再加上PyPI(Python Package Index)上50万+的第三方包,你几乎总能找到现成的轮子
动态类型与解释执行:无需编译,写完即跑。这对快速原型开发和脚本编写特别友好。当然,你也可以用类型注解+静态检查工具来获得类型安全
跨平台兼容性:写一次,到处运行——这次是真的。不像Java还需要考虑不同JVM的差异,Python的跨平台能力更加彻底
多范式编程支持:面向对象、函数式、过程式——想怎么写就怎么写。Python不像Java那样强制面向对象,你可以根据场景灵活选择编程范式
# 2、Python与Java的核心差异
从Java转到Python,最大的感受就是"轻装上阵"。但轻装不代表简陋,让我们看看两者的核心差异。
# 2.1、运行机制差异
编译型 vs 解释型
// Java: 编译后运行
javac HelloWorld.java  // 生成 .class字节码
java HelloWorld        // JVM执行字节码
# Python: 直接解释执行
python hello_world.py  # 解释器直接运行
Java是典型的编译型语言(严格说是先编译成字节码再由JVM解释执行),而Python是解释型语言。这带来几个直接影响:
- 开发速度:Python改完代码直接跑,无需编译环节,迭代更快
 - 运行性能:Java通常比Python快3-10倍(但对大多数Web应用来说,性能瓶颈在I/O而非计算)
 - 错误发现:Java在编译期就能发现类型错误,Python要到运行时才暴露(但可以用类型检查工具弥补)
 
# 2.2、类型系统差异
静态类型 vs 动态类型
这是最核心的差异之一:
// Java: 静态类型,变量类型编译期确定
String name = "张三";
name = 123;  // 编译错误!
# Python: 动态类型,变量只是对象的引用
name = "张三"
name = 123  # 完全合法,name现在指向整数对象
动态类型的优势:
- 代码更简洁,不需要写类型声明
 - 灵活性更高,鸭子类型(duck typing)让多态更自然
 
动态类型的劣势:
- 类型错误要到运行时才暴露
 - IDE的代码补全和重构能力相对较弱
 
好消息:Python 3.5+引入了类型注解,可以两全其美:
def greet(name: str) -> str:
    return f"Hello, {name}"
# 配合mypy工具做静态检查
result: int = greet("张三")  # mypy会警告类型不匹配
显式类型声明 vs 类型推断
// Java需要显式声明
Map<String, List<Integer>> data = new HashMap<>();
# Python直接推断
data = {}  # 空字典
data = {"scores": [95, 87, 92]}  # 自动推断为dict[str, list[int]]
Python的类型推断让代码更简洁,但如果你习惯了Java的明确性,也可以加上类型注解:
from typing import Dict, List
data: Dict[str, List[int]] = {"scores": [95, 87, 92]}
# 2.3、性能与内存管理
性能特性对比
| 维度 | Java | Python | 
|---|---|---|
| 启动速度 | 较慢(JVM启动开销) | 快(直接解释执行) | 
| 运行速度 | 快(JIT编译优化) | 较慢(解释执行) | 
| 内存占用 | 较大(JVM堆) | 较小 | 
| 多线程 | 真正的并行 | GIL限制(后面会讲) | 
实际项目中,Python的"慢"往往没想象中那么严重,因为:
- 性能瓶颈通常在I/O而非CPU
 - 可以用C扩展加速关键代码(NumPy、Pandas底层都是C)
 - 开发效率的提升能弥补运行效率的损失
 
内存管理机制
// Java: 垃圾回收(GC)
Object obj = new Object();
obj = null;  // 等待GC回收
# Python: 引用计数 + 垃圾回收
obj = SomeClass()
obj = None  # 引用计数为0,立即回收
Python使用引用计数作为主要内存管理机制,配合周期性垃圾回收处理循环引用。这意味着:
- 对象销毁更及时(引用计数归零即回收)
 - 但循环引用需要GC介入
 - 可以用
with语句明确管理资源生命周期 
# 2.4、代码组织与语法风格
代码组织方式
// Java: 强制面向对象,一切皆类
public class MathUtils {
    public static int add(int a, int b) {
        return a + b;
    }
}
# Python: 模块化,更灵活
# 可以直接写函数,不需要类
def add(a, b):
    return a + b
# 当然也可以用类
class MathUtils:
    @staticmethod
    def add(a, b):
        return a + b
Python的模块就是文件,不需要像Java那样包名和目录结构完全对应。一个简单的工具函数,Python可以直接写在模块级别,而Java必须套上一个类。
小结对比表
| 特性 | Java | Python | 迁移建议 | 
|---|---|---|---|
| 类型系统 | 静态 | 动态(可选注解) | 复杂项目建议用类型注解 | 
| 运行方式 | 编译+解释 | 直接解释 | 习惯热重载的快感 | 
| 性能 | 高 | 中等 | 瓶颈处考虑用C扩展 | 
| 语法风格 | 冗长严谨 | 简洁灵活 | 拥抱简洁,但注意规范 | 
| 并发模型 | 多线程友好 | 多进程为主 | 了解GIL的影响 | 
| 学习曲线 | 陡峭 | 平缓 | 但精通同样需要时间 | 
# 3、Python环境搭建
对Java开发者来说,Python的环境搭建比JDK简单多了——没有那么多版本兼容性的坑,也不需要配置CLASSPATH。
# 3.1、Python安装
截至2024年,Python 3.13是最新的稳定版本。不过实际项目中,Python 3.9+ 都是不错的选择。
Windows安装
- 访问 python.org (opens new window) 下载Windows安装包
 - 重要:安装时勾选"Add Python to PATH",这样就不用手动配置环境变量了
 - 建议选择"Custom Installation",可以选择安装位置和组件
 
# 验证安装
python --version    # 输出: Python 3.13.x
pip --version      # pip是Python的包管理器,类似Maven
macOS安装
推荐使用Homebrew,比官方安装包更方便管理:
# 安装Homebrew(如果没有)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# 安装Python
brew install python@3.13
# 验证
python3 --version
pip3 --version
Linux安装
大多数现代Linux发行版都预装了Python,但可能不是最新版本:
# Ubuntu/Debian
sudo apt update
sudo apt install python3.13 python3.13-pip python3.13-venv
# CentOS/RHEL/Fedora
sudo dnf install python3.13 python3.13-pip
# 验证
python3.13 --version
# 3.2、虚拟环境管理
Java开发者对依赖冲突应该不陌生(不同版本的同一个jar包)。Python用虚拟环境解决这个问题,类似于Docker但更轻量。
为什么需要虚拟环境?
想象一下这个场景:
- 项目A需要Django 3.2
 - 项目B需要Django 4.0
 - 全局只能安装一个版本...
 
虚拟环境让每个项目都有独立的Python环境,完美解决版本冲突。
venv——Python官方方案
# 创建虚拟环境(类似创建一个独立的Python安装)
python -m venv myproject_env
# Windows激活
myproject_env\Scripts\activate
# macOS/Linux激活
source myproject_env/bin/activate
# 激活后,命令行前缀会显示环境名
(myproject_env) $ python --version
# 退出虚拟环境
deactivate
virtualenv——第三方增强版
功能更丰富,支持更多Python版本:
# 安装
pip install virtualenv
# 创建环境(可以指定Python版本)
virtualenv -p python3.9 myproject_env
# 使用方式和venv相同
conda——数据科学界的瑞士军刀
如果你要做数据科学或机器学习,推荐conda。它不仅管理Python包,还能管理C++库、R包等:
# 安装Miniconda(轻量版)或Anaconda(完整版)
# 下载地址: https://conda.io/
# 创建环境
conda create -n myproject python=3.13
# 激活
conda activate myproject
# 安装包(conda会自动解决依赖)
conda install numpy pandas matplotlib
# 列出环境
conda env list
# 3.3、IDE与编辑器选择
从Java生态转来,你需要选择趁手的开发工具:
PyCharm——Python界的IntelliJ IDEA
JetBrains出品,界面和快捷键与IDEA类似,适合Java开发者:
- 优点:智能代码补全、强大的调试、重构工具、Git集成
 - 缺点:比较重,启动慢
 - 适合:大型项目,团队开发
 
主要功能:
- 智能代码补全和错误检测
 - 强大的调试器(类似IDEA的调试体验)
 - 内置终端和数据库工具
 - 版本控制集成
 
VS Code——微软的轻量选择
- 优点:启动快,插件丰富,内存占用小
 - 缺点:需要配置插件才能获得完整体验
 - 适合:快速开发,多语言项目
 
推荐插件:
- Python(微软官方)
 - Pylance(类型检查和智能提示)
 - Python Docstring Generator
 - GitLens
 
Jupyter Notebook——交互式开发
特别适合数据分析和机器学习:
# 安装
pip install jupyter
# 启动
jupyter notebook
# 浏览器会自动打开 http://localhost:8888
Jupyter的优势:
- 代码、文档、图表混合编写
 - 逐个单元格执行代码
 - 可视化结果直接展示
 - 支持Markdown文档
 
# 3.4、pip包管理器
pip是Python的标准包管理器,类似Maven但更简单:
pip基础命令
# 安装包
pip install requests
# 安装特定版本
pip install django==4.0
# 安装最新版本
pip install --upgrade numpy
# 卸载
pip uninstall requests
# 列出已安装的包
pip list
# 显示包信息
pip show requests
# 搜索包(已废弃,建议去PyPI网站搜索)
requirements.txt——依赖管理文件
类似于Maven的pom.xml,但更简洁:
# 生成当前环境的依赖列表
pip freeze > requirements.txt
# requirements.txt内容示例:
# Django==4.2.0
# requests==2.31.0
# numpy==1.24.3
# 在新环境中安装所有依赖
pip install -r requirements.txt
国内镜像源配置——告别龟速下载
默认pip从国外源下载,速度感人。配置国内镜像源:
临时使用:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ requests
永久配置(推荐):
Windows: 在 %APPDATA%\pip\pip.ini 文件中添加:
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple/
trusted-host = pypi.tuna.tsinghua.edu.cn
macOS/Linux: 在 ~/.pip/pip.conf 文件中添加:
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple/
trusted-host = pypi.tuna.tsinghua.edu.cn
常用国内镜像源:
- 清华大学: 
https://pypi.tuna.tsinghua.edu.cn/simple/ - 阿里云: 
https://mirrors.aliyun.com/pypi/simple/ - 腾讯云: 
https://mirrors.cloud.tencent.com/pypi/simple/ 
快速上手检验
安装完成后,让我们写第一个Python程序:
# hello.py
def greet(name):
    return f"Hello, {name}! 欢迎来到Python世界!"
if __name__ == "__main__":
    print(greet("Java开发者"))
    print("Python安装成功! 🎉")
运行:
python hello.py
如果看到输出,恭喜你,Python环境搭建成功!
小贴士:
- 建议每个项目都用独立的虚拟环境
 - requirements.txt要纳入版本控制
 - 定期更新pip本身:
python -m pip install --upgrade pip - 如果网络不稳定,可以考虑使用conda替代pip
 
# 二、Python基础语法
# 1、变量与数据类型
从Java转到Python,第一个惊喜就是:不用写类型声明了!但这不代表Python没有类型,只是更加灵活。
# 1.1、变量声明与命名规范
Python的变量声明
// Java: 必须声明类型
int age = 25;
String name = "张三";
# Python: 直接赋值即可
age = 25
name = "张三"
Python的变量本质上是对象的引用(类似Java的引用类型),赋值时会自动推断类型。
命名规范
Python和Java的命名风格有些差异:
# Python风格 - 推荐使用
user_name = "张三"          # 变量和函数:snake_case(下划线命名)
MAX_SIZE = 100             # 常量:全大写+下划线
class UserProfile:         # 类名:PascalCase(大驼峰)
    pass
# Java风格 - 在Python中不推荐
userName = "张三"           # camelCase在Python不常用
命名规则:
- 只能包含字母、数字、下划线
 - 不能以数字开头
 - 区分大小写(
name和Name是不同变量) - 不能使用Python关键字(
if、for、class等) 
特殊命名约定:
_internal_var = "私有变量"    # 单下划线开头:内部使用(约定,非强制)
__private_var = "更私有"      # 双下划线开头:名称改写(避免子类冲突)
__magic__ = "魔术方法"        # 双下划线前后:1、Python内置特殊方法-魔法方法,用于自定义类的行为;2、特殊内置属性,由解释器自动设置
# 1.2、基本数据类型
Python的类型系统比Java简单,但该有的都有。
数值类型
# int - 整数(没有大小限制!)
age = 25
big_num = 123456789012345678901234567890  # Java的long都装不下
# float - 浮点数
price = 99.99
scientific = 1.5e10  # 科学计数法:1.5 × 10^10
# complex - 复数(Java没有原生支持)
z = 3 + 4j
print(z.real)  # 输出: 3.0
print(z.imag)  # 输出: 4.0
对比Java:
// Java需要考虑大小
int age = 25;              // 32位
long bigNum = 123456L;     // 64位
BigInteger huge = new BigInteger("123..."); // 任意大小
double price = 99.99;      // 64位
float f = 99.99f;          // 32位
布尔类型
# bool - 注意首字母大写!
is_active = True   # 不是true
is_valid = False   # 不是false
# 布尔运算
result = True and False  # 使用 and,不是 &&
result = True or False   # 使用 or,不是 ||
result = not True        # 使用 not,不是 !
Python的"真值"(Truthy/Falsy)
这是Python的独特之处,以下值会被当作False:
# 这些都是"假"
bool(0)          # False
bool(0.0)        # False
bool("")         # False - 空字符串
bool([])         # False - 空列表
bool({})         # False - 空字典
bool(None)       # False
# 其他基本都是"真"
bool(1)          # True
bool("hello")    # True
bool([1, 2])     # True
这让条件判断更简洁:
# Python风格
if user_list:  # 直接判断,空列表为False
    process(user_list)
# 不需要像Java那样
# if (userList != null && !userList.isEmpty()) { ... }
字符串
# str - 字符串(不可变类型)
name = "张三"
message = 'Hello'
关于字符串的更多内容,我们在下一节详细讲解。
None类型
# None - 相当于Java的null
result = None
# 判断None
if result is None:  # 推荐用 is
    print("没有结果")
if result == None:  # 也可以,但不推荐
    print("没有结果")
对比Java:
String result = null;
if (result == null) {
    System.out.println("没有结果");
}
# 1.3、类型转换与类型检查
类型转换
# 显式转换
age_str = "25"
age = int(age_str)      # 字符串 → 整数
price = 99.99
price_int = int(price)  # 浮点 → 整数(截断,不是四舍五入)
num = 100
num_str = str(num)      # 整数 → 字符串
num_float = float(num)  # 整数 → 浮点
# 转换失败会抛异常
try:
    int("abc")  # ValueError
except ValueError as e:
    print(f"转换失败: {e}")
类型检查
# type() - 获取类型
age = 25
print(type(age))        # <class 'int'>
print(type(age) == int) # True
# isinstance() - 类型检查(推荐,支持继承)
age = 25
print(isinstance(age, int))           # True
print(isinstance(age, (int, float)))  # True - 检查多个类型
# 对比Java
# if (obj instanceof String) { ... }
类型注解(Type Hints)
Python 3.5+支持类型注解,让Java开发者更舒适:
# 加上类型注解
def greet(name: str, age: int) -> str:
    return f"Hello, {name}! You are {age} years old."
# 变量类型注解
user_name: str = "张三"
score: float = 95.5
users: list[str] = ["张三", "李四"]
# 注意:这只是"注解",运行时不会检查!
result = greet("张三", "25")  # 传了字符串,不会报错
# 需要配合mypy等工具做静态检查
# 1.4、与Java的类型系统对比
| 特性 | Java | Python | 
|---|---|---|
| 类型声明 | 强制 | 可选(类型注解) | 
| 基本类型 | 有(int, double等) | 无,一切皆对象 | 
| 包装类型 | 有(Integer, Double等) | 无需区分 | 
| 整数范围 | 固定(int 32位, long 64位) | 任意大小 | 
| 字符类型 | 有(char) | 无,用单字符字符串 | 
| 空值 | null | None | 
| 类型检查时机 | 编译期 | 运行期(可用工具静态检查) | 
实战建议:
- 小脚本可以不写类型注解,追求快速开发
 - 大项目建议加上类型注解,配合mypy检查
 - 利用Python的"鸭子类型",关注对象行为而非类型
 - 善用
isinstance()做运行时类型检查 
小技巧:
# 多重赋值
x, y, z = 1, 2, 3
# 变量交换(Java需要中间变量)
a, b = b, a
# 链式比较(Java做不到)
age = 25
if 18 <= age < 60:  # 相当于 age >= 18 and age < 60
    print("工作年龄段")
# 2、字符串操作
字符串是编程中最常用的数据类型,Python的字符串操作比Java简洁太多了。
# 2.1、字符串定义方式
单引号、双引号、三引号
# 单引号和双引号完全等价
name1 = 'Python'
name2 = "Python"
print(name1 == name2)  # True
# 优势:可以互相嵌套
message1 = "He said 'Hello'"
message2 = 'She replied "Hi"'
# 三引号:多行字符串(相当于Java的文本块)
long_text = """
这是一段
多行文本
可以随意换行
"""
sql = '''
SELECT * FROM users
WHERE age > 18
  AND status = 'active'
'''
对比Java(Java 15+才支持文本块):
// Java 15+
String sql = """
    SELECT * FROM users
    WHERE age > 18
      AND status = 'active'
    """;
# 2.2、字符串格式化
Python有三种字符串格式化方式,推荐使用f-string(最现代、最简洁)。
% 格式化(老式写法)
name = "张三"
age = 25
# 类似C语言的printf
message = "我叫%s,今年%d岁" % (name, age)
print(message)  # 我叫张三,今年25岁
# 格式控制
price = 99.999
print("价格:%.2f元" % price)  # 价格:100.00元
str.format()(Python 2.6+)
name = "张三"
age = 25
# 位置参数
message = "我叫{},今年{}岁".format(name, age)
# 索引参数
message = "我叫{0},今年{1}岁,{0}很高兴认识你".format(name, age)
# 命名参数(推荐,可读性好)
message = "我叫{name},今年{age}岁".format(name=name, age=age)
# 格式控制
price = 99.999
print("价格:{:.2f}元".format(price))  # 价格:100.00元
# 填充和对齐
print("{:>10}".format("右对齐"))   # "      右对齐"
print("{:<10}".format("左对齐"))   # "左对齐      "
print("{:^10}".format("居中"))     # "   居中   "
print("{:0>5}".format("42"))      # "00042"
f-string(Python 3.6+,强烈推荐!)
name = "张三"
age = 25
score = 95.678
# 最简洁的方式
message = f"我叫{name},今年{age}岁"
# 可以直接在{}中写表达式
print(f"明年我{age + 1}岁")
print(f"成绩:{score:.2f}分")  # 成绩:95.68分
# 支持复杂表达式
users = ["张三", "李四", "王五"]
print(f"共有{len(users)}个用户")
# 可以调用方法
text = "hello"
print(f"大写:{text.upper()}")  # 大写:HELLO
# 多行f-string
message = (
    f"姓名:{name}\n"
    f"年龄:{age}\n"
    f"成绩:{score:.2f}"
)
# Python 3.8+ 支持 = 调试
x = 10
print(f"{x=}")  # x=10(显示变量名和值,调试利器)
对比Java:
// Java传统方式
String message = String.format("我叫%s,今年%d岁", name, age);
// Java 15+ 文本块 + formatted()
String message = """
    姓名:%s
    年龄:%d
    """.formatted(name, age);
# 2.3、常用字符串方法
Python的字符串方法非常丰富,而且都返回新字符串(字符串是不可变的)。
大小写转换
text = "Hello World"
print(text.upper())       # HELLO WORLD
print(text.lower())       # hello world
print(text.capitalize())  # Hello world(首字母大写)
print(text.title())       # Hello World(每个单词首字母大写)
print(text.swapcase())    # hELLO wORLD(大小写互换)
查找和判断
text = "Hello Python"
# 查找子串
print(text.find("Python"))      # 6(返回索引)
print(text.find("Java"))        # -1(找不到)
print(text.index("Python"))     # 6(找不到会抛异常)
# 判断
print(text.startswith("Hello")) # True
print(text.endswith("Python"))  # True
print("123".isdigit())          # True(是否全是数字)
print("abc".isalpha())          # True(是否全是字母)
print("abc123".isalnum())       # True(是否全是字母或数字)
print("  ".isspace())           # True(是否全是空白字符)
替换和分割
text = "Hello Python Python"
# 替换
print(text.replace("Python", "Java"))        # Hello Java Java
print(text.replace("Python", "Java", 1))     # Hello Java Python(只替换1次)
# 分割
csv = "张三,25,北京"
parts = csv.split(",")
print(parts)  # ['张三', '25', '北京']
# 多行分割
text = "第一行\n第二行\n第三行"
lines = text.splitlines()
print(lines)  # ['第一行', '第二行', '第三行']
# 连接(反向操作)
words = ["Hello", "Python", "World"]
result = " ".join(words)
print(result)  # Hello Python World
对比Java:
// Java需要更多代码
String[] parts = csv.split(",");
String result = String.join(" ", words);
去除空白
text = "  Hello Python  "
print(text.strip())   # "Hello Python"(去除两端空白)
print(text.lstrip())  # "Hello Python  "(去除左侧)
print(text.rstrip())  # "  Hello Python"(去除右侧)
# 去除指定字符
url = "https://example.com/"
print(url.rstrip("/"))  # https://example.com
# 2.4、字符串切片操作
这是Python的特色功能,比Java的substring()灵活多了!
基本切片
text = "Python"
# 语法:[start:end:step]
print(text[0])      # P(单个字符)
print(text[0:3])    # Pyt(索引0到2,不包含3)
print(text[:3])     # Pyt(省略start,从头开始)
print(text[3:])     # hon(省略end,到末尾)
print(text[:])      # Python(完整复制)
# 负索引(从右往左数)
print(text[-1])     # n(最后一个字符)
print(text[-3:])    # hon(最后3个字符)
print(text[:-1])    # Pytho(除了最后一个)
# 步长
print(text[::2])    # Pto(每隔一个取一个)
print(text[::-1])   # nohtyP(反转字符串!)
对比Java:
// Java需要用substring
String text = "Python";
String sub = text.substring(0, 3);  // Pyt
// 反转需要StringBuilder
String reversed = new StringBuilder(text).reverse().toString();
切片的实用技巧
# 去除文件扩展名
filename = "document.pdf"
name = filename[:-4]  # document
# 提取域名
email = "user@example.com"
domain = email[email.index("@")+1:]  # example.com
# 每隔N个字符插入分隔符
card = "1234567890123456"
formatted = "-".join([card[i:i+4] for i in range(0, len(card), 4)])
print(formatted)  # 1234-5678-9012-3456
# 2.5、原始字符串与转义字符
转义字符
# 常见转义字符
print("第一行\n第二行")     # 换行
print("姓名:\t张三")       # 制表符
print("路径:C:\\Users")    # 反斜杠
print("他说:\"你好\"")     # 双引号
原始字符串(raw string)
# 正则表达式和Windows路径特别有用
path = r"C:\Users\张三\Documents"  # 不需要转义
regex = r"\d+\.\d+"                # 正则表达式
# 对比普通字符串
path_normal = "C:\\Users\\张三\\Documents"  # 需要双反斜杠
对比Java:
// Java也需要转义
String path = "C:\\Users\\张三\\Documents";
// Java 15+ 支持原始字符串字面量(预览特性)
Unicode字符
# Unicode字符
print("\u4e2d\u6587")  # 中文
print("\U0001F600")    # 😀(emoji)
# Python 3默认UTF-8,直接写中文和emoji
message = "你好 🎉"
字符串的不可变性
text = "Python"
# text[0] = "J"  # TypeError: 'str' object does not support item assignment
# 需要创建新字符串
text = "J" + text[1:]  # "Jython"
# 或者用replace
text = text.replace("P", "J")
# 2.6、字符串性能提示
拼接大量字符串
# ❌ 错误方式:在循环中用+拼接(O(n²)复杂度)
result = ""
for i in range(1000):
    result += str(i)
# ✅ 正确方式:用join(O(n)复杂度)
result = "".join(str(i) for i in range(1000))
# ✅ 或者用列表积累再join
parts = []
for i in range(1000):
    parts.append(str(i))
result = "".join(parts)
对比Java:
// Java也是同样的道理
// ❌ String result = "";
//    for (int i = 0; i < 1000; i++) result += i;
// ✅ StringBuilder sb = new StringBuilder();
//    for (int i = 0; i < 1000; i++) sb.append(i);
//    String result = sb.toString();
小结对比表
| 操作 | Java | Python | 
|---|---|---|
| 格式化 | String.format() | f-string(推荐) | 
| 分割 | split() | split() | 
| 连接 | String.join() | str.join() | 
| 替换 | replace() | replace() | 
| 切片 | substring() | [start:end] | 
| 反转 | StringBuilder.reverse() | [::-1] | 
| 多行文本 | """..."""(Java 15+) | """...""" | 
Python的字符串操作更简洁直观,尤其是f-string和切片语法,能大大提高开发效率!
# 3、运算符
Python的运算符和Java大部分相似,但也有一些独特的地方,特别是成员运算符和身份运算符。
# 3.1、算术运算符
a = 10
b = 3
print(a + b)   # 13 - 加法
print(a - b)   # 7  - 减法
print(a * b)   # 30 - 乘法
print(a / b)   # 3.333... - 除法(注意:总是返回浮点数!)
print(a // b)  # 3  - 整除(向下取整)
print(a % b)   # 1  - 取模
print(a ** b)  # 1000 - 幂运算(10的3次方)
重点差异:
// Java
int a = 10, b = 3;
System.out.println(a / b);  // 3(整数除法)
# Python
a, b = 10, 3
print(a / b)   # 3.3333...(总是浮点除法)
print(a // b)  # 3(整除)
幂运算是Python的特色:
# Python有专门的幂运算符
print(2 ** 10)  # 1024
# Java需要用Math.pow()
# Math.pow(2, 10)
复合赋值:
x = 10
x += 5   # x = x + 5
x -= 3   # x = x - 3
x *= 2   # x = x * 2
x /= 4   # x = x / 4
x //= 2  # x = x // 2
x %= 3   # x = x % 3
x **= 2  # x = x ** 2
# 3.2、比较运算符
a = 10
b = 20
print(a == b)   # False - 等于
print(a != b)   # True  - 不等于
print(a > b)    # False - 大于
print(a < b)    # True  - 小于
print(a >= b)   # False - 大于等于
print(a <= b)   # True  - 小于等于
链式比较(Python独有,超级实用!):
age = 25
# Python可以这样写
if 18 <= age < 60:
    print("工作年龄段")
# 相当于(但更简洁)
if age >= 18 and age < 60:
    print("工作年龄段")
# 多重比较
x = 5
if 1 < x < 10 < 100:  # 完全合法!
    print("x在1到10之间,10小于100")
对比Java:
// Java不支持链式比较
if (age >= 18 && age < 60) {
    System.out.println("工作年龄段");
}
# 3.3、逻辑运算符
# Python使用英文单词,更易读
a = True
b = False
print(a and b)   # False - 逻辑与(Java用&&)
print(a or b)    # True  - 逻辑或(Java用||)
print(not a)     # False - 逻辑非(Java用!)
短路求值:
# and:如果第一个为False,不会计算第二个
def expensive_check():
    print("执行了昂贵的检查")
    return True
x = False
if x and expensive_check():  # expensive_check()不会执行
    print("都为真")
# or:如果第一个为True,不会计算第二个
x = True
if x or expensive_check():  # expensive_check()不会执行
    print("至少一个为真")
逻辑运算的返回值(Python的独特之处):
# and返回第一个假值,或最后一个值
print(5 and 10)      # 10(都为真,返回最后一个)
print(0 and 10)      # 0(第一个为假)
print("" and "abc")  # ""(空字符串为假)
# or返回第一个真值,或最后一个值
print(5 or 10)       # 5(第一个为真)
print(0 or 10)       # 10(第一个为假,返回第二个)
print("" or "abc")   # "abc"
# 实用技巧:提供默认值
name = input_name or "匿名用户"  # 如果input_name为空,使用默认值
# 3.4、位运算符
与Java完全相同:
a = 60  # 0011 1100
b = 13  # 0000 1101
print(a & b)   # 12 (0000 1100) - 按位与
print(a | b)   # 61 (0011 1101) - 按位或
print(a ^ b)   # 49 (0011 0001) - 按位异或
print(~a)      # -61 - 按位取反
print(a << 2)  # 240 (1111 0000) - 左移
print(a >> 2)  # 15 (0000 1111) - 右移
# 3.5、成员运算符(Python独有)
这是Python的特色,超级好用!
# in - 检查元素是否在序列中
fruits = ["苹果", "香蕉", "橙子"]
print("苹果" in fruits)      # True
print("葡萄" in fruits)      # False
# not in - 检查元素是否不在序列中
print("葡萄" not in fruits)  # True
# 适用于各种容器
text = "Hello Python"
print("Python" in text)      # True
numbers = {1, 2, 3, 4, 5}
print(3 in numbers)          # True
user_dict = {"name": "张三", "age": 25}
print("name" in user_dict)   # True(检查键)
对比Java:
// Java需要用contains()方法
List<String> fruits = Arrays.asList("苹果", "香蕉", "橙子");
boolean hasApple = fruits.contains("苹果");
// 或者字符串的contains()
String text = "Hello Python";
boolean hasPython = text.contains("Python");
实用场景:
# 验证输入
command = input("请输入命令: ")
if command not in ["start", "stop", "restart"]:
    print("无效命令")
# 过滤数据
valid_ids = {1, 2, 3, 4, 5}
if user_id in valid_ids:
    process_user(user_id)
# 字符串检查
email = "user@example.com"
if "@" not in email:
    print("邮箱格式错误")
# 3.6、身份运算符(Python独有)
用于判断两个变量是否引用同一个对象(不是值相等,是对象相等)。
# is - 判断是否是同一个对象
a = [1, 2, 3]
b = a        # b指向同一个列表对象
c = [1, 2, 3]  # c是新的列表对象
print(a is b)      # True - 指向同一对象
print(a is c)      # False - 不同对象
print(a == c)      # True - 但值相等
# is not
print(a is not c)  # True
何时使用is?
# ✅ 检查None(推荐用is)
result = some_function()
if result is None:
    print("没有返回值")
# ✅ 检查单例对象
if obj is True:   # 检查是否是True对象
    pass
# ❌ 不要用is比较值
x = 1000
y = 1000
if x is y:  # 可能是False!(小整数有缓存,大整数没有)
    print("相等")
# ✅ 应该用==比较值
if x == y:  # 正确
    print("相等")
小整数缓存机制:
# Python缓存了-5到256的整数
a = 10
b = 10
print(a is b)  # True - 指向同一个缓存对象
# 大整数不缓存
a = 1000
b = 1000
print(a is b)  # False(通常,取决于实现)
print(a == b)  # True - 但值相等
# 3.7、运算符优先级
从高到低排列:
| 优先级 | 运算符 | 说明 | 
|---|---|---|
| 1 | ** |  幂运算 | 
| 2 | ~, +x, -x |  按位取反、正号、负号 | 
| 3 | *, /, //, % |  乘、除、整除、取模 | 
| 4 | +, - |  加、减 | 
| 5 | <<, >> |  位移 | 
| 6 | & |  按位与 | 
| 7 | ^ |  按位异或 | 
| 8 | \| |  按位或 | 
| 9 | ==, !=, >, <, >=, <=, is, is not, in, not in |  比较运算 | 
| 10 | not |  逻辑非 | 
| 11 | and |  逻辑与 | 
| 12 | or |  逻辑或 | 
实例:
# 复杂表达式
result = 2 + 3 * 4 ** 2  # 先幂运算(16),再乘法(48),最后加法(50)
print(result)  # 50
# 建议:复杂表达式加括号提高可读性
result = 2 + (3 * (4 ** 2))  # 更清晰
# 逻辑运算
x = 5
result = x > 3 and x < 10 or x == 0  # (x > 3 and x < 10) or (x == 0)
print(result)  # True
三元运算符(Python版本):
# Python的三元表达式
age = 25
status = "成年" if age >= 18 else "未成年"
# 对比Java
// String status = age >= 18 ? "成年" : "未成年";
# 可以嵌套(但不推荐,影响可读性)
score = 85
grade = "优秀" if score >= 90 else "良好" if score >= 80 else "及格" if score >= 60 else "不及格"
海象运算符 := (Python 3.8+)
在表达式中赋值:
# 传统写法
n = len(some_list)
if n > 10:
    print(f"列表很长,有{n}个元素")
# 使用海象运算符
if (n := len(some_list)) > 10:
    print(f"列表很长,有{n}个元素")
# 在while循环中特别有用
while (line := file.readline()) != "":
    process(line)
小结对比
| 特性 | Java | Python | 
|---|---|---|
| 除法 | /返回整数 |  /总是返回浮点数 | 
| 整除 | 用/ |  专门的// | 
| 幂运算 | Math.pow() |  **运算符 | 
| 逻辑运算 | &&, \|\|, ! |  and, or, not | 
| 成员检查 | contains() |  in, not in | 
| 身份检查 | == |  is, is not | 
| 三元运算 | a ? b : c |  b if a else c | 
| 链式比较 | 不支持 | a < b < c | 
# 4、控制流
Python的控制流语法比Java简洁,用缩进代替花括号,强制写出更清晰的代码结构。
# 4.1、if-elif-else条件语句
基本语法
age = 25
# 简单if语句
if age >= 18:
    print("成年人")
# if-else
if age >= 18:
    print("成年人")
else:
    print("未成年")
# if-elif-else(相当于Java的if-else if-else)
if age < 18:
    print("少年")
elif age < 60:
    print("成年")
else:
    print("老年")
对比Java:
// Java需要花括号
if (age >= 18) {
    System.out.println("成年人");
} else if (age < 60) {
    System.out.println("成年");
} else {
    System.out.println("老年");
}
Python的优势:
# 链式比较
score = 85
if 90 <= score <= 100:
    grade = "A"
elif 80 <= score < 90:
    grade = "B"
elif 70 <= score < 80:
    grade = "C"
else:
    grade = "D"
# 成员运算符让条件更简洁
command = "start"
if command in ["start", "run", "begin"]:
    print("启动程序")
elif command in ["stop", "end", "quit"]:
    print("停止程序")
else:
    print("未知命令")
利用Python的"真值"特性:
# ✅ Pythonic写法
name = input("请输入姓名: ")
if name:  # 空字符串为False
    print(f"欢迎, {name}")
else:
    print("姓名不能为空")
# ✅ 检查列表是否为空
users = get_users()
if users:  # 空列表为False
    for user in users:
        print(user)
else:
    print("没有用户")
# 对比Java
// if (name != null && !name.isEmpty()) { ... }
// if (users != null && !users.isEmpty()) { ... }
# 4.2、while循环
基本语法
# 简单while循环
count = 0
while count < 5:
    print(f"第{count + 1}次循环")
    count += 1  # Python没有++运算符
# 无限循环
while True:
    user_input = input("输入'quit'退出: ")
    if user_input == "quit":
        break
    print(f"你输入了: {user_input}")
对比Java:
// Java
int count = 0;
while (count < 5) {
    System.out.println("第" + (count + 1) + "次循环");
    count++;  // Java有++运算符
}
while-else(Python独有)
# while正常结束时执行else
search_list = [1, 3, 5, 7, 9]
target = 6
while search_list:
    item = search_list.pop(0)
    if item == target:
        print(f"找到了: {target}")
        break
else:
    print(f"没找到: {target}")  # 只有while正常结束才执行
# 如果用break退出,else不会执行
# 4.3、for循环与迭代器
这是Python最强大的特性之一!
遍历序列
# 遍历列表
fruits = ["苹果", "香蕉", "橙子"]
for fruit in fruits:
    print(fruit)
# 遍历字符串
for char in "Python":
    print(char)
# 遍历字典
user = {"name": "张三", "age": 25, "city": "北京"}
# 遍历键
for key in user:
    print(key)
# 遍历值
for value in user.values():
    print(value)
# 遍历键值对
for key, value in user.items():
    print(f"{key}: {value}")
对比Java:
// Java需要更多代码
List<String> fruits = Arrays.asList("苹果", "香蕉", "橙子");
// 传统for循环
for (int i = 0; i < fruits.size(); i++) {
    System.out.println(fruits.get(i));
}
// 增强for循环
for (String fruit : fruits) {
    System.out.println(fruit);
}
enumerate() - 同时获取索引和值
fruits = ["苹果", "香蕉", "橙子"]
# 同时获取索引和值
for index, fruit in enumerate(fruits):
    print(f"{index}: {fruit}")
# 从指定索引开始
for index, fruit in enumerate(fruits, start=1):
    print(f"第{index}个: {fruit}")
zip() - 并行遍历多个序列
names = ["张三", "李四", "王五"]
ages = [25, 30, 35]
cities = ["北京", "上海", "广州"]
# 并行遍历
for name, age, city in zip(names, ages, cities):
    print(f"{name}, {age}岁, 来自{city}")
# 结果:
# 张三, 25岁, 来自北京
# 李四, 30岁, 来自上海
# 王五, 35岁, 来自广州
# 4.4、range()函数
专门用于生成数字序列,在for循环中特别有用。
# range(stop) - 从0开始
for i in range(5):
    print(i)  # 0, 1, 2, 3, 4
# range(start, stop) - 指定开始和结束
for i in range(2, 8):
    print(i)  # 2, 3, 4, 5, 6, 7
# range(start, stop, step) - 指定步长
for i in range(0, 10, 2):
    print(i)  # 0, 2, 4, 6, 8
# 反向
for i in range(10, 0, -1):
    print(i)  # 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
# 生成列表(但通常不需要)
numbers = list(range(5))  # [0, 1, 2, 3, 4]
实用场景:
# 传统的C风格循环
data = ["a", "b", "c", "d"]
for i in range(len(data)):
    print(f"索引{i}: {data[i]}")
# 但更Pythonic的方式是用enumerate
for i, item in enumerate(data):
    print(f"索引{i}: {item}")
# 创建嵌套列表(二维数组)
matrix = []
for i in range(3):
    row = []
    for j in range(4):
        row.append(i * 4 + j)
    matrix.append(row)
# 4.5、break、continue、pass
break - 跳出循环
# 在for循环中使用
for i in range(10):
    if i == 5:
        break
    print(i)  # 0, 1, 2, 3, 4
# 在while循环中使用
count = 0
while True:
    if count >= 3:
        break
    print(f"计数: {count}")
    count += 1
# 只跳出最内层循环
for i in range(3):
    for j in range(3):
        if j == 1:
            break  # 只跳出内层循环
        print(f"i={i}, j={j}")
continue - 跳过本次循环
# 跳过偶数
for i in range(10):
    if i % 2 == 0:
        continue
    print(i)  # 1, 3, 5, 7, 9
# 处理文件,跳过空行
lines = ["第一行", "", "第三行", "", "第五行"]
for line in lines:
    if not line:  # 空字符串为False
        continue
    print(f"处理: {line}")
pass - 占位符
# 在开发中作为占位符
def future_function():
    pass  # 暂时不实现,避免语法错误
# 条件分支占位
score = 85
if score >= 90:
    pass  # 暂时不处理优秀情况
elif score >= 60:
    print("及格")
else:
    print("不及格")
# 类定义占位
class MyClass:
    pass  # 暂时空的类
# 异常处理占位
try:
    risky_operation()
except SpecificError:
    pass  # 忽略特定错误
# 4.6、循环中的else子句
Python独有的特性,很多人不知道但很有用!
for-else
# else在循环正常结束时执行
numbers = [2, 4, 6, 8]
for num in numbers:
    if num % 2 != 0:  # 查找奇数
        print(f"找到奇数: {num}")
        break
else:
    print("所有数字都是偶数")  # 循环正常结束执行
# 搜索场景
users = ["张三", "李四", "王五"]
target = "赵六"
for user in users:
    if user == target:
        print(f"找到用户: {user}")
        break
else:
    print(f"用户 {target} 不存在")  # 没找到时执行
while-else
# 密码验证(最多3次机会)
attempts = 0
max_attempts = 3
while attempts < max_attempts:
    password = input("请输入密码: ")
    if password == "123456":
        print("密码正确,登录成功!")
        break
    attempts += 1
    print(f"密码错误,还有{max_attempts - attempts}次机会")
else:
    print("密码错误次数过多,账户锁定!")  # 循环正常结束执行
# 4.7、嵌套循环与性能优化
嵌套循环
# 九九乘法表
for i in range(1, 10):
    for j in range(1, i + 1):
        print(f"{j}×{i}={i*j}", end="\t")
    print()  # 换行
# 查找重复元素
numbers = [1, 2, 3, 4, 2, 5, 3]
duplicates = []
for i in range(len(numbers)):
    for j in range(i + 1, len(numbers)):
        if numbers[i] == numbers[j] and numbers[i] not in duplicates:
            duplicates.append(numbers[i])
print(f"重复元素: {duplicates}")
性能优化技巧
# ❌ 低效:每次都调用len()
data = list(range(1000))
for i in range(len(data)):
    process(data[i])
# ✅ 高效:直接迭代
for item in data:
    process(item)
# ❌ 低效:在循环中进行复杂计算
for i in range(1000):
    result = expensive_calculation()  # 每次都计算
    process(i, result)
# ✅ 高效:提前计算
result = expensive_calculation()  # 只计算一次
for i in range(1000):
    process(i, result)
# ❌ 低效:字符串拼接
result = ""
for i in range(1000):
    result += str(i)
# ✅ 高效:使用join
result = "".join(str(i) for i in range(1000))
# 4.8、实用的控制流技巧
Pythonic的代码提示
# 提示:这里展示的简洁写法将在第6章"数据结构"中详细讲解
# 包括列表推导式、字典推导式等Python特有语法
# 传统循环 vs Pythonic写法
# 传统方式
squares = []
for x in range(10):
    squares.append(x ** 2)
# Pythonic方式(见第6章详解)
squares = [x ** 2 for x in range(10)]
多个条件的优雅处理
# 使用元组
def get_season(month):
    if month in (12, 1, 2):
        return "冬季"
    elif month in (3, 4, 5):
        return "春季"
    elif month in (6, 7, 8):
        return "夏季"
    elif month in (9, 10, 11):
        return "秋季"
    else:
        return "无效月份"
# 使用字典(更高效)
SEASON_MAP = {
    1: "冬季", 2: "冬季", 3: "春季", 4: "春季",
    5: "春季", 6: "夏季", 7: "夏季", 8: "夏季",
    9: "秋季", 10: "秋季", 11: "秋季", 12: "冬季"
}
def get_season_fast(month):
    return SEASON_MAP.get(month, "无效月份")
小结对比表
| 特性 | Java | Python | 
|---|---|---|
| 代码块 | 花括号{} |  缩进 | 
| else if | else if |  elif | 
| 循环后清理 | finally块 | else子句 | 
| 遍历容器 | 增强for循环 | for item in container | 
| 同时获取索引 | 手动计数 | enumerate() | 
| 并行遍历 | 复杂 | zip() | 
| 数字序列 | 手动创建 | range() | 
| 占位符 | 空语句; |  pass | 
Python的控制流设计哲学是"简洁即是美",用更少的代码实现更清晰的逻辑!
# 5、数据结构与推导式
Python的内置数据结构非常强大,比Java的集合框架更简洁易用。特别值得一提的是Python的推导式语法,它让集合操作变得极其优雅。理解这些概念是掌握Python的关键。
# 5.1、列表(list)
列表是Python最常用的数据结构,相当于Java的ArrayList,但功能更强大。
基本操作
# 创建列表
fruits = ["苹果", "香蕉", "橙子"]
numbers = [1, 2, 3, 4, 5]
mixed = ["Python", 3.14, True, None]  # 可以存储不同类型
# 访问元素
print(fruits[0])     # 苹果
print(fruits[-1])    # 橙子(负索引:从右往左)
# 修改元素
fruits[1] = "葡萄"
print(fruits)        # ['苹果', '葡萄', '橙子']
# 列表长度
print(len(fruits))   # 3
列表操作方法
fruits = ["苹果", "香蕉"]
# 添加元素
fruits.append("橙子")                # 末尾添加
fruits.insert(1, "葡萄")             # 指定位置插入
fruits.extend(["芒果", "草莓"])        # 批量添加
print(fruits)  # ['苹果', '葡萄', '香蕉', '橙子', '芒果', '草莓']
# 删除元素
fruits.remove("香蕉")                # 删除指定元素
last_fruit = fruits.pop()           # 删除并返回最后一个
second_fruit = fruits.pop(1)        # 删除并返回指定位置
del fruits[0]                       # 直接删除指定位置
# 查找元素
if "苹果" in fruits:
    index = fruits.index("苹果")     # 返回首次出现的索引
    count = fruits.count("苹果")     # 统计出现次数
# 排序
numbers = [3, 1, 4, 1, 5, 9]
numbers.sort()                      # 原地排序
print(numbers)                      # [1, 1, 3, 4, 5, 9]
sorted_nums = sorted([3, 1, 4])     # 返回新列表
numbers.reverse()                   # 原地反转
对比Java:
// Java需要更多代码
List<String> fruits = new ArrayList<>();
fruits.add("苹果");
fruits.add("香蕉");
fruits.remove("香蕉");
Collections.sort(fruits);
列表切片
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 基本切片
print(numbers[2:5])     # [2, 3, 4](不包含索引5)
print(numbers[:3])      # [0, 1, 2](前3个)
print(numbers[7:])      # [7, 8, 9](从索引7到末尾)
print(numbers[:])       # 完整复制
# 步长切片
print(numbers[::2])     # [0, 2, 4, 6, 8](每隔一个)
print(numbers[1::2])    # [1, 3, 5, 7, 9](奇数位置)
print(numbers[::-1])    # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0](反转)
# 切片赋值(很强大!)
numbers[2:5] = [20, 30, 40]         # 替换一段
numbers[2:2] = [15, 25]             # 插入
numbers[2:4] = []                   # 删除
列表推导式(List Comprehension)
这是Python的杀手级特性!
# 传统方式
squares = []
for x in range(10):
    squares.append(x ** 2)
# 列表推导式(一行搞定)
squares = [x ** 2 for x in range(10)]
# 带条件的推导式
even_squares = [x ** 2 for x in range(10) if x % 2 == 0]
# [0, 4, 16, 36, 64]
# 复杂处理
words = ["hello", "world", "python"]
capitalized = [word.upper() for word in words if len(word) > 4]
# ['HELLO', 'WORLD', 'PYTHON']
# 嵌套推导式(慎用,影响可读性)
matrix = [[x * y for x in range(3)] for y in range(3)]
# [[0, 0, 0], [0, 1, 2], [0, 2, 4]]
# 5.2、元组(tuple)
元组是不可变的序列,相当于只读的列表。
基本特性
# 创建元组
point = (3, 4)
colors = ("红", "绿", "蓝")
single = (42,)        # 单元素元组需要逗号
empty = ()            # 空元组
# 或者省略括号
point = 3, 4
colors = "红", "绿", "蓝"
# 访问元素(和列表一样)
print(point[0])       # 3
print(colors[-1])     # 蓝
# 不能修改
# point[0] = 5        # TypeError
元组解包(Tuple Unpacking)
point = (3, 4)
# 解包赋值
x, y = point
print(f"坐标:({x}, {y})")
# 函数返回多个值
def get_name_age():
    return "张三", 25
name, age = get_name_age()
# 交换变量(Python独有)
a, b = 10, 20
a, b = b, a           # 交换,无需中间变量
# 扩展解包(Python 3+)
numbers = (1, 2, 3, 4, 5)
first, *middle, last = numbers
print(first)          # 1
print(middle)         # [2, 3, 4]
print(last)           # 5
元组的用途
# 1. 函数返回多个值
def divmod_custom(a, b):
    return a // b, a % b
quotient, remainder = divmod_custom(10, 3)
# 2. 作为字典的键(必须不可变)
locations = {
    (0, 0): "原点",
    (1, 1): "对角线",
    (3, 4): "某个点"
}
# 3. 配置和常量
DEFAULT_CONFIG = ("localhost", 8080, "utf-8")
HOST, PORT, ENCODING = DEFAULT_CONFIG
# a、命名元组(namedtuple)
普通元组通过索引访问元素,可读性较差。namedtuple(命名元组)让你可以通过名称访问,同时保持元组的不可变性和性能优势。
from collections import namedtuple
# 定义命名元组
Point = namedtuple('Point', ['x', 'y'])
# 创建实例
p1 = Point(3, 4)
p2 = Point(x=10, y=20)
# 通过名称访问(更清晰)
print(p1.x, p1.y)        # 3 4
# 也支持索引访问(兼容普通元组)
print(p1[0], p1[1])      # 3 4
# 不可变
# p1.x = 5               # AttributeError
定义方式对比
# 方式1:列表形式
Point = namedtuple('Point', ['x', 'y'])
# 方式2:空格分隔字符串
Point = namedtuple('Point', 'x y')
# 方式3:逗号分隔字符串
Point = namedtuple('Point', 'x, y')
实际应用
# 1. 表示坐标点
Point = namedtuple('Point', ['x', 'y'])
p = Point(3, 4)
print(f"坐标: ({p.x}, {p.y})")
# 2. 数据库查询结果
Student = namedtuple('Student', ['name', 'age', 'score'])
students = [
    Student('张三', 20, 85),
    Student('李四', 21, 92),
    Student('王五', 19, 78)
]
for s in students:
    print(f"{s.name}: {s.score}分")
# 3. 函数返回多个值(更清晰)
def get_user_info():
    User = namedtuple('User', ['name', 'age', 'email'])
    return User('张三', 25, 'zhang@example.com')
user = get_user_info()
print(user.name)    # 张三
print(user.email)   # zhang@example.com
常用方法
Point = namedtuple('Point', ['x', 'y'])
p = Point(3, 4)
# 转换为字典
print(p._asdict())
# {'x': 3, 'y': 4}
# 替换字段(返回新对象)
p2 = p._replace(x=10)
print(p2)           # Point(x=10, y=4)
print(p)            # Point(x=3, y=4)(原对象不变)
# 字段名称
print(p._fields)    # ('x', 'y')
# 从序列创建
data = [5, 6]
p3 = Point._make(data)
print(p3)           # Point(x=5, y=6)
扩展命名元组
# 添加默认值(Python 3.7+)
Point = namedtuple('Point', ['x', 'y'], defaults=[0, 0])
p1 = Point()         # Point(x=0, y=0)
p2 = Point(3)        # Point(x=3, y=0)
p3 = Point(3, 4)     # Point(x=3, y=4)
# 继承并添加方法
from collections import namedtuple
class Point(namedtuple('Point', ['x', 'y'])):
    """扩展的点类"""
    __slots__ = ()  # 节省内存
    def distance_from_origin(self):
        """计算到原点的距离"""
        return (self.x ** 2 + self.y ** 2) ** 0.5
    def __str__(self):
        return f"({self.x}, {self.y})"
p = Point(3, 4)
print(p.distance_from_origin())  # 5.0
print(p)                         # (3, 4)
对比普通元组
# 普通元组:可读性差
person = ("张三", 25, "北京")
print(person[0])    # 张三(需要记住索引含义)
print(person[1])    # 25
# 命名元组:可读性强
Person = namedtuple('Person', ['name', 'age', 'city'])
person = Person("张三", 25, "北京")
print(person.name)  # 张三(语义清晰)
print(person.age)   # 25
优势与限制
优势:
- ✅ 可读性强(通过名称访问)
 - ✅ 不可变(线程安全)
 - ✅ 内存效率高(比字典节省内存)
 - ✅ 可以作为字典键
 - ✅ 兼容普通元组(支持索引和解包)
 
限制:
- ❌ 不可变(不能修改字段值)
 - ❌ 不支持默认值(Python 3.7之前)
 - ❌ 字段名在定义后不能修改
 
对比Java:
// Java需要定义完整的类
public class Point {
    private final int x;
    private final int y;
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public int getX() { return x; }
    public int getY() { return y; }
}
// 或使用Java 14+ Record(更接近namedtuple)
public record Point(int x, int y) {}
何时使用namedtuple
- ✅ 需要轻量级的不可变数据容器
 - ✅ 表示固定字段的记录(如坐标、配置)
 - ✅ 函数返回多个值时提高可读性
 - ✅ 替代字典以节省内存
 - ❌ 需要可变数据时(用dataclass或普通类)
 - ❌ 需要复杂行为时(用普通类)
 
# 5.3、字典(dict)
字典是键值对映射,相当于Java的HashMap,但使用更简单。
基本操作
# 创建字典
user = {"name": "张三", "age": 25, "city": "北京"}
empty_dict = {}
scores = dict(math=95, english=87, physics=92)
# 访问和修改
print(user["name"])          # 张三
print(user.get("phone"))     # None(键不存在时返回None)
print(user.get("phone", "未设置"))  # 未设置(提供默认值)
user["age"] = 26             # 修改
user["phone"] = "13800138000" # 添加新键
# 删除
del user["city"]             # 删除键值对
phone = user.pop("phone")    # 删除并返回值
last_item = user.popitem()   # 删除并返回最后一个键值对
字典方法
user = {"name": "张三", "age": 25, "city": "北京"}
# 获取所有键、值、键值对
print(user.keys())           # dict_keys(['name', 'age', 'city'])
print(user.values())         # dict_values(['张三', 25, '北京'])
print(user.items())          # dict_keys([('name', '张三'), ('age', 25), ('city', '北京')])
# 遍历字典
for key in user:
    print(f"{key}: {user[key]}")
for key, value in user.items():
    print(f"{key}: {value}")
# 合并字典
defaults = {"theme": "dark", "lang": "zh"}
user.update(defaults)        # 合并到user中
# Python 3.9+ 合并运算符
# config = defaults | user
字典推导式
# 传统方式
squares = {}
for x in range(5):
    squares[x] = x ** 2
# 字典推导式
squares = {x: x ** 2 for x in range(5)}
# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# 带条件
even_squares = {x: x ** 2 for x in range(10) if x % 2 == 0}
# 处理现有数据
words = ["apple", "banana", "cherry"]
word_lengths = {word: len(word) for word in words}
# {'apple': 5, 'banana': 6, 'cherry': 6}
有序字典特性(Python 3.7+)
# Python 3.7+字典保持插入顺序
user = {"name": "张三", "age": 25}
user["city"] = "北京"
print(list(user.keys()))  # ['name', 'age', 'city'](保持顺序)
# 在早期版本中,如需有序字典:
from collections import OrderedDict
ordered_dict = OrderedDict([("a", 1), ("b", 2)])
# 5.4、集合(set)
集合是无序且不重复的元素集合,类似Java的HashSet。
基本操作
# 创建集合
fruits = {"苹果", "香蕉", "橙子"}
numbers = set([1, 2, 3, 4, 5])
empty_set = set()            # 注意:{}是空字典
# 添加和删除元素
fruits.add("葡萄")
fruits.remove("香蕉")        # 不存在会报错
fruits.discard("芒果")       # 不存在不报错
popped = fruits.pop()        # 随机删除并返回
# 成员检查(很快!)
print("苹果" in fruits)      # True
集合运算
set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}
# 并集
print(set1 | set2)          # {1, 2, 3, 4, 5, 6, 7, 8}
print(set1.union(set2))
# 交集
print(set1 & set2)          # {4, 5}
print(set1.intersection(set2))
# 差集
print(set1 - set2)          # {1, 2, 3}
print(set1.difference(set2))
# 对称差集(异或)
print(set1 ^ set2)          # {1, 2, 3, 6, 7, 8}
print(set1.symmetric_difference(set2))
# 子集和超集
print({1, 2}.issubset(set1))     # True
print(set1.issuperset({1, 2}))   # True
集合推导式
# 去重并处理
numbers = [1, 2, 2, 3, 3, 4, 5]
unique_squares = {x ** 2 for x in numbers}
# {1, 4, 9, 16, 25}
# 实际应用:去重
emails = ["user1@example.com", "user2@example.com", "user1@example.com"]
unique_emails = set(emails)
frozenset(不可变集合)
# 创建不可变集合
immutable_set = frozenset([1, 2, 3, 4])
# 可以作为字典的键
cache = {
    frozenset([1, 2]): "结果1",
    frozenset([3, 4]): "结果2"
}
# 不能修改
# immutable_set.add(5)  # AttributeError
# 5.5、与Java集合框架对比
对比表
| Python | Java | 特点 | 
|---|---|---|
list |  ArrayList |  动态数组,可变 | 
tuple |  无直接对应 | 不可变序列 | 
dict |  HashMap |  键值映射,Python 3.7+有序 | 
set |  HashSet |  无序不重复集合 | 
frozenset |  无直接对应 | 不可变集合 | 
语法对比
// Java - 创建和操作
List<String> list = new ArrayList<>();
list.add("item");
String item = list.get(0);
Map<String, Integer> map = new HashMap<>();
map.put("key", 42);
Integer value = map.get("key");
Set<String> set = new HashSet<>();
set.add("item");
boolean exists = set.contains("item");
# Python - 更简洁
list = ["item"]
list.append("item2")
item = list[0]
dict = {"key": 42}
dict["key2"] = 43
value = dict["key"]
set = {"item"}
set.add("item2")
exists = "item" in set
实用技巧
# 列表去重并保持顺序
def unique_list(items):
    seen = set()
    result = []
    for item in items:
        if item not in seen:
            seen.add(item)
            result.append(item)
    return result
# 或者用dict(Python 3.7+)
def unique_list_dict(items):
    # dict.fromkeys 快速创建一个新字典,键为items中的元素,值为None
    return list(dict.fromkeys(items))
# 统计元素频率
from collections import Counter
words = ["apple", "banana", "apple", "cherry", "banana", "apple"]
frequency = Counter(words)
print(frequency)  # Counter({'apple': 3, 'banana': 2, 'cherry': 1})
# 默认值字典
from collections import defaultdict
# defaultdict 创建一个默认值为空列表的dict
groups = defaultdict(list)
for name, score in [("张三", 95), ("李四", 87), ("张三", 92)]:
    groups[name].append(score)
print(dict(groups))  # {'张三': [95, 92], '李四': [87]}
选择指南
- list:需要有序、可变、允许重复的序列
 - tuple:需要不可变的序列,如坐标、配置
 - dict:需要键值映射,如配置、缓存、索引
 - set:需要去重、快速成员检查、集合运算
 - frozenset:需要不可变的集合,如字典的键
 
Python的数据结构设计精妙,掌握它们就能写出更Pythonic的代码!
# 6、函数定义与使用
Python的函数比Java的方法更灵活强大,支持多种参数传递方式,而且函数是"一等公民"。
# 6.1、函数定义语法
基本语法
# 简单函数
def greet(name):
    return f"Hello, {name}!"
# 带类型注解的函数(推荐)
def add(a: int, b: int) -> int:
    """计算两个数的和"""
    return a + b
# 无返回值的函数
def print_info(name: str, age: int) -> None:
    print(f"姓名: {name}, 年龄: {age}")
# 文档字符串(Docstring)
def calculate_area(radius: float) -> float:
    """
    计算圆的面积
    Args:
        radius: 圆的半径
    Returns:
        圆的面积
    Raises:
        ValueError: 当半径为负数时
    """
    if radius < 0:
        raise ValueError("半径不能为负数")
    return 3.14159 * radius ** 2
对比Java:
// Java需要更多样板代码
public class MathUtils {
    /**
     * 计算两个数的和
     */
    public static int add(int a, int b) {
        return a + b;
    }
    public static void printInfo(String name, int age) {
        System.out.println("姓名: " + name + ", 年龄: " + age);
    }
}
# 6.2、参数传递
Python的参数传递机制非常灵活,支持多种方式。
位置参数
def introduce(name, age, city):
    return f"我叫{name},{age}岁,来自{city}"
# 按位置传递
result = introduce("张三", 25, "北京")
关键字参数
# 可以按任意顺序传递
result = introduce(city="北京", name="张三", age=25)
# 混合使用(位置参数必须在前)
result = introduce("张三", age=25, city="北京")
默认参数
def greet(name, greeting="Hello", punctuation="!"):
    return f"{greeting}, {name}{punctuation}"
print(greet("张三"))                    # Hello, 张三!
print(greet("张三", "你好"))             # 你好, 张三!
print(greet("张三", punctuation="?"))   # Hello, 张三?
# 注意:默认参数的陷阱。在 Python 中,函数的默认参数在函数定义时(def 时)被创建一次,而不是每次调用时重新创建。
# [] 这个列表对象在函数定义时就创建了,所有后续调用共享同一个列表对象。
def append_to_list(item, target_list=[]):  # ❌ 危险!
    target_list.append(item)
    return target_list
# 正确的写法
def append_to_list(item, target_list=None):  # ✅ 正确
    if target_list is None:
        target_list = []
    target_list.append(item)
    return target_list
**可变参数(*args 和 kwargs)
# *args - 可变位置参数
def sum_all(*numbers):
    """计算所有数字的和"""
    return sum(numbers)
print(sum_all(1, 2, 3, 4, 5))  # 15
print(sum_all(10, 20))         # 30
# **kwargs - 可变关键字参数
def create_user(**kwargs):
    """创建用户信息"""
    user = {}
    for key, value in kwargs.items():
        user[key] = value
    return user
user = create_user(name="张三", age=25, city="北京", job="程序员")
print(user)  # {'name': '张三', 'age': 25, 'city': '北京', 'job': '程序员'}
# 混合使用
def flexible_function(required, *args, **kwargs):
    print(f"必需参数: {required}")
    print(f"位置参数: {args}")
    print(f"关键字参数: {kwargs}")
flexible_function("必须的", 1, 2, 3, name="张三", age=25)
参数解包
# 解包列表/元组
def calculate(a, b, c):
    return a + b * c
numbers = [2, 3, 4]
result = calculate(*numbers)  # 相当于 calculate(2, 3, 4)
# 解包字典
def greet(name, age, city):
    return f"{name}, {age}岁, 来自{city}"
person = {"name": "张三", "age": 25, "city": "北京"}
message = greet(**person)  # 相当于 greet(name="张三", age=25, city="北京")
# 6.3、返回值与多返回值
单个返回值
def square(x):
    return x ** 2
def get_greeting():
    return "Hello, World!"
# 没有明确return,返回None
def print_message(msg):
    print(msg)
    # 隐式返回 None
多返回值(元组解包)
def get_name_age():
    return "张三", 25  # 实际返回元组
# 解包接收
name, age = get_name_age()
def divmod_custom(a, b):
    return a // b, a % b  # 商和余数
quotient, remainder = divmod_custom(17, 5)
print(f"商: {quotient}, 余数: {remainder}")  # 商: 3, 余数: 2
# 复杂的多返回值
def analyze_data(data):
    total = sum(data)
    count = len(data)
    average = total / count if count > 0 else 0
    return total, count, average, min(data), max(data)
data = [1, 5, 3, 9, 2]
total, count, avg, min_val, max_val = analyze_data(data)
# 6.4、函数作为一等公民
Python中函数是对象,可以赋值、传递、存储。
函数赋值
def greet(name):
    return f"Hello, {name}!"
# 函数赋值给变量
say_hello = greet
print(say_hello("张三"))  # Hello, 张三!
# 函数存储在数据结构中
operations = {
    "add": lambda x, y: x + y,
    "subtract": lambda x, y: x - y,
    "multiply": lambda x, y: x * y
}
result = operations["add"](5, 3)  # 8
函数作为参数
def apply_operation(numbers, operation):
    """对数字列表应用操作"""
    return [operation(x) for x in numbers]
def square(x):
    return x ** 2
def cube(x):
    return x ** 3
numbers = [1, 2, 3, 4, 5]
squares = apply_operation(numbers, square)   # [1, 4, 9, 16, 25]
cubes = apply_operation(numbers, cube)       # [1, 8, 27, 64, 125]
# 使用内置函数
data = ["hello", "WORLD", "Python"]
uppercase = list(map(str.upper, data))      # ['HELLO', 'WORLD', 'PYTHON']
lengths = list(map(len, data))              # [5, 5, 6]
函数返回函数
def create_multiplier(factor):
    """创建一个乘法函数"""
    def multiplier(x):
        return x * factor
    return multiplier
double = create_multiplier(2)
triple = create_multiplier(3)
print(double(5))  # 10
print(triple(4))  # 12
# 装饰器的基础
def timer_decorator(func):
    import time
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} 执行时间: {end - start:.4f}秒")
        return result
    return wrapper
@timer_decorator
def slow_function():
    import time
    time.sleep(1)
    return "完成"
# 6.5、lambda表达式
lambda是创建匿名函数的简洁方式。
基本语法
# 基本lambda
square = lambda x: x ** 2
print(square(5))  # 25
# 多参数lambda
add = lambda x, y: x + y
print(add(3, 4))  # 7
# 对比普通函数
def square_func(x):
    return x ** 2
# 效果相同,但lambda更简洁
实际应用
# 排序
students = [("张三", 85), ("李四", 92), ("王五", 78)]
# 按成绩排序
by_score = sorted(students, key=lambda student: student[1])
print(by_score)  # [('王五', 78), ('张三', 85), ('李四', 92)]
# 过滤
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens)  # [2, 4, 6, 8, 10]
# 映射
squares = list(map(lambda x: x ** 2, range(5)))
print(squares)  # [0, 1, 4, 9, 16]
# 字典操作
users = [
    {"name": "张三", "age": 25},
    {"name": "李四", "age": 30},
    {"name": "王五", "age": 22}
]
# 按年龄排序
sorted_users = sorted(users, key=lambda user: user["age"])
# 6.6、作用域与LEGB规则
Python使用LEGB规则解析变量名。
LEGB规则
- Local(局部作用域)
 - Enclosing(嵌套函数的外层作用域)
 - Global(全局作用域)
 - Built-in(内置作用域)
 
x = "全局变量"
def outer():
    x = "外层函数变量"
    def inner():
        x = "内层函数变量"
        print(f"内层: {x}")  # 内层函数变量
    inner()
    print(f"外层: {x}")      # 外层函数变量
outer()
print(f"全局: {x}")          # 全局变量
global和nonlocal关键字
count = 0  # 全局变量
def increment_global():
    # 在函数内部读取或修改模块级别(全局)的变量
    global count
    count += 1
def create_counter():
    count = 0  # 局部变量
    def increment():
        # 在嵌套函数中修改外层函数的局部变量(不是全局变量)
        nonlocal count
        count += 1
        return count
    return increment
# 使用
increment_global()
print(count)  # 1
counter = create_counter()
print(counter())  # 1
print(counter())  # 2
# 6.7、闭包
闭包是函数和其周围状态的组合。
基本闭包
def create_adder(x):
    def adder(y):
        return x + y  # 捕获外层变量x
    return adder
add_5 = create_adder(5)
add_10 = create_adder(10)
print(add_5(3))   # 8
print(add_10(3))  # 13
# 检查闭包变量
print(add_5.__closure__)  # (<cell at 0x...: int object at 0x...>,)
实际应用
# 计数器
def create_counter(start=0):
    count = start
    def counter():
        nonlocal count
        count += 1
        return count
    def reset():
        nonlocal count
        count = start
    def get_count():
        return count
    # 返回多个函数
    counter.reset = reset
    counter.get_count = get_count
    return counter
counter = create_counter(10)
print(counter())         # 11
print(counter())         # 12
print(counter.get_count())  # 12
counter.reset()
print(counter())         # 11
# 配置工厂
def create_formatter(prefix, suffix):
    def formatter(text):
        return f"{prefix}{text}{suffix}"
    return formatter
html_formatter = create_formatter("<p>", "</p>")
markdown_formatter = create_formatter("**", "**")
print(html_formatter("Hello"))     # <p>Hello</p>
print(markdown_formatter("Bold"))  # **Bold**
装饰器简介
# 提示:装饰器是Python的重要特性,将在第8章"高级特性"中详细讲解
# 这里简要展示装饰器与闭包的关系
def timer_decorator(func):
    """简单的计时装饰器(第8章详解)"""
    import time
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} 执行时间: {end - start:.4f}秒")
        return result
    return wrapper
# 使用装饰器
@timer_decorator
def slow_function():
    import time
    time.sleep(1)
    return "完成"
与Java对比
| 特性 | Java | Python | 
|---|---|---|
| 函数定义 | 必须在类中 | 可以独立存在 | 
| 方法重载 | 支持(不同参数) | 不支持(用默认参数) | 
| 可变参数 | ...语法 |  *args, **kwargs | 
| 函数对象 | 需要接口/lambda | 函数即对象 | 
| 闭包 | lambda表达式 | 完整闭包支持 | 
| 作用域 | 块级作用域 | 函数级作用域 | 
Python的函数系统比Java更灵活,支持函数式编程范式,能写出更简洁优雅的代码!
# 7、模块与包
Python的模块系统比Java的包系统更简单直观,一个.py文件就是一个模块,文件夹就是包。
# 7.1、模块导入方式
import语句
# 导入整个模块
import math
print(math.pi)        # 3.141592653589793
print(math.sqrt(16))  # 4.0
import os
print(os.getcwd())    # 获取当前工作目录
# 导入多个模块
import sys, json, re
# 导入时重命名
import datetime as dt
now = dt.datetime.now()
from...import语句
# 导入模块中的特定函数/类
from math import pi, sqrt, sin
print(pi)      # 直接使用,无需前缀
print(sqrt(16)) # 4.0
# 导入多个
from os import getcwd, listdir, path
# 导入所有(不推荐)
from math import *  # 可能造成命名冲突
# 导入时重命名
from datetime import datetime as dt
now = dt.now()
import别名
# 常见的别名约定
import numpy as np           # 数据科学常用
import pandas as pd          # 数据分析
import matplotlib.pyplot as plt  # 绘图
# 自定义模块别名
import my_very_long_module_name as short_name
对比Java:
// Java的import
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
// 静态导入
import static java.lang.Math.PI;
import static java.lang.Math.sqrt;
# 7.2、模块搜索路径
Python按以下顺序搜索模块:
import sys
# 查看模块搜索路径
for path in sys.path:
    print(path)
# 1. 当前脚本所在目录
# 2. PYTHONPATH环境变量指定的目录
# 3. Python标准库目录
# 4. site-packages目录(第三方包)
# 动态添加搜索路径
sys.path.append('/path/to/my/modules')
sys.path.insert(0, '/priority/path')  # 优先搜索
查找模块位置
import math
print(math.__file__)  # 显示模块文件位置
# 或者用inspect模块
import inspect
import requests
print(inspect.getfile(requests))
# 7.3、__name__变量与入口点
 这是Python模块系统的重要概念。
# my_module.py
def hello():
    print("Hello from my_module!")
def main():
    print("这是主程序")
    hello()
# 关键代码:模块的入口点
if __name__ == "__main__":
    main()
工作原理
# 当直接运行脚本时
# python my_module.py
# __name__ 的值是 "__main__"
# 当被其他模块导入时
# import my_module
# __name__ 的值是 "my_module"
# 实际应用
def add(a, b):
    return a + b
def multiply(a, b):
    return a * b
# 测试代码,只在直接运行时执行
if __name__ == "__main__":
    # 这里的代码只在直接运行时执行,导入时不执行
    print("测试模块功能...")
    print(f"2 + 3 = {add(2, 3)}")
    print(f"4 * 5 = {multiply(4, 5)}")
对比Java:
// Java的main方法
public class MyClass {
    public static void add(int a, int b) {
        return a + b;
    }
    public static void main(String[] args) {
        // 程序入口点
        System.out.println("2 + 3 = " + add(2, 3));
    }
}
# 7.4、包的组织结构
包就是包含__init__.py文件的目录。
基本包结构
mypackage/
    __init__.py      # 包的初始化文件
    module1.py       # 模块1
    module2.py       # 模块2
    subpackage/      # 子包
        __init__.py
        submodule.py
创建包
# mypackage/__init__.py
"""
我的Python包
"""
# 包级别的变量
__version__ = "1.0.0"
__author__ = "张三"
# 导入子模块,方便使用
from .module1 import function1
from .module2 import Class2
# 定义包的公开接口
__all__ = ["function1", "Class2", "helper_function"]
def helper_function():
    return "这是包级别的函数"
# mypackage/module1.py
def function1():
    return "来自模块1的函数"
def internal_function():
    return "内部函数"
# mypackage/module2.py
class Class2:
    def method(self):
        return "来自类2的方法"
# 7.5、__init__.py文件的作用
 __init__.py让目录变成Python包,并控制包的导入行为。
基本作用
# 空的__init__.py
# 仅仅让目录成为包
# 或者包含初始化代码
print("正在初始化mypackage...")
# 导入子模块
from .database import connect
from .utils import helper
# 设置包级别变量
VERSION = "2.1.0"
DEBUG = False
控制导入
# mypackage/__init__.py
# 只导出特定的函数/类
from .core import important_function
from .helpers import utility_class
# 控制 from mypackage import * 的行为
__all__ = [
    "important_function",
    "utility_class",
    "VERSION"
]
VERSION = "1.0.0"
# 初始化代码
def _initialize():
    print("包初始化完成")
_initialize()
使用包
# 导入包
import mypackage
print(mypackage.VERSION)
result = mypackage.function1()
# 导入包中的模块
from mypackage import module1
result = module1.function1()
# 导入特定功能
from mypackage.module2 import Class2
obj = Class2()
# 7.6、相对导入与绝对导入
绝对导入(推荐)
# 总是从顶级包开始
from mypackage.subpackage import submodule
from mypackage.module1 import function1
import mypackage.database.models
相对导入
# 在包内部使用相对导入
# mypackage/module1.py
# 导入同级模块
from . import module2          # 当前包的module2
from .module2 import Class2    # 当前包module2的Class2
# 导入上级包
from .. import parent_module   # 上级包的模块
from ..utils import helper     # 上级包utils的helper
# 导入子包
from .subpackage import submodule  # 子包的模块
最佳实践
# ✅ 推荐:使用绝对导入
from myproject.database import models
from myproject.utils.helpers import format_date
# ✅ 包内相对导入也可以
from .database import models
from ..utils import helpers
# ❌ 避免:隐式相对导入(Python 3已移除)
# import models  # 不清楚来源
# 7.7、实际项目结构示例
典型的Python项目结构
myproject/
    README.md
    requirements.txt     # 依赖列表
    # 注意:现代 Python 推荐使用 pyproject.toml(PEP 518/621)作为首选打包配置方式,但 setup.py 仍广泛使用,尤其在旧项目中
    setup.py            # 安装脚本
    myproject/          # 主包
        __init__.py
        main.py         # 程序入口
        config.py       # 配置
        models/         # 数据模型
            __init__.py
            user.py
            product.py
        views/          # 视图层
            __init__.py
            api.py
            web.py
        utils/          # 工具函数
            __init__.py
            helpers.py
            validators.py
        tests/          # 测试代码
            __init__.py
            test_models.py
            test_views.py
配置模块
# myproject/config.py
import os
class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-secret')
    DATABASE_URL = os.environ.get('DATABASE_URL', 'sqlite:///app.db')
    DEBUG = os.environ.get('DEBUG', 'False').lower() == 'true'
class DevelopmentConfig(Config):
    DEBUG = True
class ProductionConfig(Config):
    DEBUG = False
# 根据环境选择配置
config = {
    'development': DevelopmentConfig,
    'production': ProductionConfig,
    'default': DevelopmentConfig
}
主程序入口
# myproject/main.py
from myproject.config import config
from myproject.models import User
from myproject.utils.helpers import format_date
def main():
    cfg = config['default']()
    if cfg.DEBUG:
        print("运行在调试模式")
    # 业务逻辑
    user = User("张三", 25)
    print(f"用户: {user.name}, 注册日期: {format_date(user.created_at)}")
if __name__ == "__main__":
    main()
# 7.8、第三方包管理
使用pip安装包
# 安装单个包
pip install requests
# 安装特定版本
pip install django==4.2.0
# 从requirements.txt安装
pip install -r requirements.txt
# 安装开发版本
pip install git+https://github.com/user/repo.git
requirements.txt示例
# 生产依赖
Django>=4.1,<5.0
requests>=2.28.0
psycopg2-binary==2.9.3
# 开发依赖(通常放在dev-requirements.txt)
pytest>=7.0.0
black>=22.0.0
flake8>=5.0.0
虚拟环境中的包管理
# 创建虚拟环境
python -m venv myproject_env
# 激活环境
# Windows
myproject_env\Scripts\activate
# macOS/Linux
source myproject_env/bin/activate
# 安装包
pip install -r requirements.txt
# 导出当前环境的包列表
pip freeze > requirements.txt
# 退出环境
deactivate
与Java对比
| 特性 | Java | Python | 
|---|---|---|
| 基本单位 | 类(必须在包中) | 模块(.py文件) | 
| 包声明 | package com.example |  目录+__init__.py | 
| 导入 | import com.example.Class |  from package import module | 
| 依赖管理 | Maven/Gradle | pip+requirements.txt | 
| 项目结构 | 强制目录结构 | 灵活的目录结构 | 
| 模块搜索 | CLASSPATH | sys.path | 
实用技巧
# 动态导入模块
import importlib
module_name = "math"
math_module = importlib.import_module(module_name)
print(math_module.pi)
# 检查模块是否存在
try:
    import optional_module
    HAS_OPTIONAL = True
except ImportError:
    HAS_OPTIONAL = False
# 条件导入
if HAS_OPTIONAL:
    from optional_module import feature
# 延迟导入(在函数内部导入)
def process_data():
    import pandas as pd  # 只在需要时导入
    return pd.DataFrame()
# 获取模块信息
import inspect
import requests
print(f"模块名: {requests.__name__}")
print(f"模块文件: {requests.__file__}")
print(f"模块文档: {requests.__doc__}")
Python的模块系统设计简洁优雅,比Java的包系统更容易理解和使用。掌握模块和包的概念,能帮你更好地组织代码和管理项目!
# 三、面向对象编程
# 1、类与对象
Python的面向对象编程比Java更灵活,没有那么多严格的规则,但同样强大。
# 1.1、类的定义
基本语法
# 简单的类定义
class Person:
    """这是一个人类"""
    pass  # 空类,占位符
# 带属性和方法的类
class Dog:
    """狗类"""
    # 类属性(所有实例共享)
    species = "Canis familiaris"
    def bark(self):
        """实例方法"""
        return "汪汪汪!"
# 创建对象(实例化)
dog = Dog()
print(dog.species)  # Canis familiaris
print(dog.bark())   # 汪汪汪!
对比Java:
// Java需要更多样板代码
public class Dog {
    // 类属性(静态)
    public static final String SPECIES = "Canis familiaris";
    // 实例方法
    public String bark() {
        return "汪汪汪!";
    }
}
// 实例化
Dog dog = new Dog();
# 1.2、构造函数(__init__)
 Python使用__init__方法初始化对象,类似Java的构造函数。
基本构造函数
class Person:
    def __init__(self, name, age):
        """构造函数,创建对象时自动调用"""
        self.name = name  # 实例属性
        self.age = age
    def introduce(self):
        return f"我叫{self.name},{self.age}岁"
# 创建对象
person = Person("张三", 25)
print(person.introduce())  # 我叫张三,25岁
带默认值的构造函数
class User:
    def __init__(self, username, email, is_active=True, role="user"):
        self.username = username
        self.email = email
        self.is_active = is_active
        self.role = role
    def __repr__(self):
        return f"User(username='{self.username}', email='{self.email}')"
# 使用默认值
user1 = User("张三", "zhangsan@example.com")
# 覆盖默认值
user2 = User("李四", "lisi@example.com", is_active=False, role="admin")
对比Java:
// Java的构造函数
public class Person {
    private String name;
    private int age;
    // 构造函数
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    // 需要手动写getter/setter
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}
# 1.3、实例属性与类属性
实例属性
class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner      # 实例属性
        self.balance = balance  # 每个实例独立
    def deposit(self, amount):
        self.balance += amount
        return self.balance
account1 = BankAccount("张三", 1000)
account2 = BankAccount("李四", 2000)
account1.deposit(500)
print(account1.balance)  # 1500
print(account2.balance)  # 2000(互不影响)
类属性
class BankAccount:
    # 类属性(所有实例共享)
    bank_name = "Python银行"
    interest_rate = 0.03
    account_count = 0
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance
        # 修改类属性(通过类名)
        BankAccount.account_count += 1
    @classmethod
    def get_account_count(cls):
        """类方法,访问类属性"""
        return cls.account_count
# 访问类属性
print(BankAccount.bank_name)  # Python银行
# 实例也可以访问
account = BankAccount("张三", 1000)
print(account.bank_name)      # Python银行
# 创建多个实例
account1 = BankAccount("张三")
account2 = BankAccount("李四")
print(BankAccount.get_account_count())  # 2
实例属性 vs 类属性
class Example:
    class_var = "类属性"  # 类属性
    def __init__(self, value):
        self.instance_var = value  # 实例属性
# 访问类属性
print(Example.class_var)  # 类属性
# 实例访问
obj1 = Example("实例1")
obj2 = Example("实例2")
print(obj1.instance_var)  # 实例1
print(obj2.instance_var)  # 实例2
# 修改类属性
Example.class_var = "新的类属性"
print(obj1.class_var)  # 新的类属性(所有实例都变了)
print(obj2.class_var)  # 新的类属性
# 注意:实例赋值会创建同名的实例属性,不会修改类属性
obj1.class_var = "实例属性"
print(obj1.class_var)        # 实例属性(实例的)
print(obj2.class_var)        # 新的类属性(类的)
print(Example.class_var)     # 新的类属性(类的)
# 1.4、实例方法、类方法、静态方法
实例方法
class Calculator:
    def __init__(self, name):
        self.name = name
    # 实例方法:第一个参数是self
    def add(self, a, b):
        return a + b
    def greet(self):
        return f"我是{self.name}计算器"
calc = Calculator("科学")
print(calc.add(2, 3))   # 5
print(calc.greet())     # 我是科学计算器
类方法
class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day
    # 类方法:第一个参数是cls(类本身)
    @classmethod
    def from_string(cls, date_string):
        """工厂方法:从字符串创建日期"""
        year, month, day = map(int, date_string.split('-'))
        return cls(year, month, day)  # 返回类的实例
    @classmethod
    def today(cls):
        """工厂方法:创建今天的日期"""
        import datetime
        now = datetime.date.today()
        return cls(now.year, now.month, now.day)
    # 面向用户的可读字符串
    def __str__(self):
        return f"{self.year}-{self.month:02d}-{self.day:02d}"
# 使用类方法
date1 = Date.from_string("2024-10-26")
date2 = Date.today()
print(date1)  # 2024-10-26
print(date2)  # 当前日期
静态方法
class MathUtils:
    # 静态方法:不需要self或cls
    @staticmethod
    def is_even(number):
        """检查是否是偶数"""
        return number % 2 == 0
    @staticmethod
    def factorial(n):
        """计算阶乘"""
        if n <= 1:
            return 1
        return n * MathUtils.factorial(n - 1)
# 使用静态方法(无需创建实例)
print(MathUtils.is_even(4))    # True
print(MathUtils.factorial(5))  # 120
# 也可以通过实例调用
utils = MathUtils()
print(utils.is_even(3))        # False
三种方法的对比
| 方法类型 | 第一个参数 | 装饰器 | 访问方式 | 用途 | 
|---|---|---|---|---|
| 实例方法 | self |  无 | 实例调用 | 操作实例数据 | 
| 类方法 | cls |  @classmethod |  类/实例调用 | 工厂方法、操作类属性 | 
| 静态方法 | 无 | @staticmethod |  类/实例调用 | 工具函数、不需要访问类/实例数据 | 
对比Java:
public class Example {
    private String name;
    // 实例方法
    public void instanceMethod() {
        System.out.println(this.name);
    }
    // 静态方法
    public static void staticMethod() {
        System.out.println("静态方法");
    }
}
# 1.5、私有属性与方法
Python没有真正的私有属性,使用命名约定来表示。
命名约定
class BankAccount:
    def __init__(self, owner, balance):
        self.owner = owner             # 公开属性
        self._balance = balance        # 单下划线:受保护(约定)
        self.__pin = "1234"            # 双下划线:私有(名称改写)
    def get_balance(self):
        """公开方法访问私有数据"""
        return self._balance
    def _internal_method(self):
        """受保护方法(约定)"""
        return "内部使用"
    def __private_method(self):
        """私有方法"""
        return "真正的私有"
    def check_pin(self, pin):
        return self.__pin == pin
account = BankAccount("张三", 1000)
# 公开属性
print(account.owner)         # 张三
# 受保护属性(可以访问,但不推荐)
print(account._balance)      # 1000
# 私有属性(名称改写为 _BankAccount__pin)
# print(account.__pin)       # AttributeError
print(account._BankAccount__pin)  # 1234(强制访问,不推荐)
# 通过公开方法访问
print(account.get_balance())  # 1000
print(account.check_pin("1234"))  # True
最佳实践
class User:
    def __init__(self, username, password):
        self.username = username      # 公开
        self._email = None            # 受保护(内部使用)
        self.__password_hash = self._hash_password(password)  # 私有
    def _hash_password(self, password):
        """受保护方法:密码哈希"""
        # 简化示例
        return hash(password)
    def verify_password(self, password):
        """公开方法:验证密码"""
        return self.__password_hash == self._hash_password(password)
对比Java:
public class BankAccount {
    public String owner;        // 公开
    protected double balance;   // 受保护
    private String pin;         // 私有
    // 私有方法
    private void privateMethod() {
        // ...
    }
}
# 1.6、属性访问器(property装饰器)
使用@property创建getter和setter,让方法像属性一样访问。
基本用法
class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius
    # getter
    @property
    def celsius(self):
        """摄氏温度"""
        return self._celsius
    # setter
    @celsius.setter
    def celsius(self, value):
        if value < -273.15:
            raise ValueError("温度不能低于绝对零度")
        self._celsius = value
    # 只读属性(只有getter)
    @property
    def fahrenheit(self):
        """华氏温度(只读)"""
        return self._celsius * 9/5 + 32
# 使用
temp = Temperature(25)
print(temp.celsius)      # 25(调用getter)
print(temp.fahrenheit)   # 77.0
temp.celsius = 30        # 调用setter
print(temp.celsius)      # 30
# temp.fahrenheit = 100  # AttributeError(只读)
# temp.celsius = -300    # ValueError(验证失败)
实际应用
class Person:
    def __init__(self, name, age):
        self._name = name
        self._age = age
    @property
    def name(self):
        """姓名(只读)"""
        return self._name
    @property
    def age(self):
        """年龄"""
        return self._age
    @age.setter
    def age(self, value):
        if not isinstance(value, int):
            raise TypeError("年龄必须是整数")
        if value < 0 or value > 150:
            raise ValueError("年龄必须在0-150之间")
        self._age = value
    @property
    def is_adult(self):
        """是否成年(计算属性)"""
        return self._age >= 18
person = Person("张三", 25)
print(person.name)       # 张三
print(person.age)        # 25
print(person.is_adult)   # True
person.age = 30          # 使用setter
# person.name = "李四"   # AttributeError(只读)
删除器(deleter)
class Resource:
    def __init__(self, name):
        self._name = name
        self._loaded = False
    @property
    def name(self):
        return self._name
    @property
    def data(self):
        if not self._loaded:
            print("加载数据...")
            self._loaded = True
        return f"数据: {self._name}"
    @data.deleter
    def data(self):
        """删除数据"""
        print("清理数据...")
        self._loaded = False
resource = Resource("文件.txt")
print(resource.data)     # 加载数据... 数据: 文件.txt
print(resource.data)     # 数据: 文件.txt(已加载)
del resource.data        # 清理数据...
print(resource.data)     # 加载数据... 数据: 文件.txt
对比Java:
public class Temperature {
    private double celsius;
    // getter
    public double getCelsius() {
        return celsius;
    }
    // setter
    public void setCelsius(double value) {
        if (value < -273.15) {
            throw new IllegalArgumentException("温度不能低于绝对零度");
        }
        this.celsius = value;
    }
    // 计算属性
    public double getFahrenheit() {
        return celsius * 9/5 + 32;
    }
}
// 使用
Temperature temp = new Temperature();
temp.setCelsius(25);          // 必须调用方法
double c = temp.getCelsius(); // 必须调用方法
property的优势
# Python使用@property,像访问属性一样
person.age = 30        # 自然的语法
temp = person.age
# Java必须调用方法
person.setAge(30);     // 方法调用
int temp = person.getAge();
# Python可以在不破坏接口的情况下添加逻辑
class Circle:
    def __init__(self, radius):
        self.radius = radius  # 最初是普通属性
    # 后来添加验证,无需修改调用代码
    @property
    def radius(self):
        return self._radius
    @radius.setter
    def radius(self, value):
        if value < 0:
            raise ValueError("半径不能为负数")
        self._radius = value
小结对比表
| 特性 | Java | Python | 
|---|---|---|
| 类定义 | class Name { } |  class Name: | 
| 构造函数 | public Name() { } |  def __init__(self): | 
| 实例属性 | private Type field; |  self.field = value | 
| 类属性 | static Type field; |  类级别定义 | 
| 私有成员 | private |  __name(名称改写) | 
| 受保护成员 | protected |  _name(约定) | 
| getter/setter | 手动编写 | @property | 
| 类方法 | static |  @classmethod | 
| 静态方法 | static |  @staticmethod | 
Python的类设计更简洁,没有Java那么多访问修饰符,通过约定和装饰器实现类似功能!
# 2、继承与多态
Python的继承机制比Java更灵活,支持多继承,并有独特的方法解析顺序(MRO)。
# 2.1、单继承
基本语法
# 父类(基类)
class Animal:
    def __init__(self, name):
        self.name = name
    def speak(self):
        return "发出声音"
    def info(self):
        return f"我是{self.name}"
# 子类(派生类)
class Dog(Animal):
    def __init__(self, name, breed):
        # 调用父类构造函数
        super().__init__(name)
        self.breed = breed
    # 重写父类方法
    def speak(self):
        return "汪汪汪!"
    # 新增方法
    def fetch(self):
        return f"{self.name}去捡球了"
# 使用
dog = Dog("旺财", "金毛")
print(dog.info())     # 我是旺财(继承自Animal)
print(dog.speak())    # 汪汪汪!(重写了)
print(dog.fetch())    # 旺财去捡球了(新方法)
对比Java:
// Java的继承
public class Animal {
    protected String name;
    public Animal(String name) {
        this.name = name;
    }
    public String speak() {
        return "发出声音";
    }
}
public class Dog extends Animal {
    private String breed;
    public Dog(String name, String breed) {
        super(name);  // 调用父类构造函数
        this.breed = breed;
    }
    @Override
    public String speak() {
        return "汪汪汪!";
    }
}
isinstance()和issubclass()
class Animal:
    pass
class Dog(Animal):
    pass
dog = Dog()
# isinstance: 检查实例类型
print(isinstance(dog, Dog))     # True
print(isinstance(dog, Animal))  # True(子类实例也是父类实例)
print(isinstance(dog, object))  # True(所有类都继承自object)
# issubclass: 检查继承关系
print(issubclass(Dog, Animal))   # True
print(issubclass(Animal, Dog))   # False
print(issubclass(Dog, object))   # True
# 2.2、多继承与MRO(方法解析顺序)
Python支持多继承,一个类可以继承多个父类。
基本多继承
class Flyable:
    def fly(self):
        return "能飞"
class Swimmable:
    def swim(self):
        return "能游泳"
class Duck(Flyable, Swimmable):
    def quack(self):
        return "嘎嘎嘎"
# 使用
duck = Duck()
print(duck.fly())      # 能飞
print(duck.swim())     # 能游泳
print(duck.quack())    # 嘎嘎嘎
MRO(Method Resolution Order)
当多个父类有同名方法时,Python使用C3线性化算法确定调用顺序。
class A:
    def method(self):
        return "A的方法"
class B(A):
    def method(self):
        return "B的方法"
class C(A):
    def method(self):
        return "C的方法"
class D(B, C):
    pass
# 查看MRO
print(D.__mro__)
# (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
d = D()
print(d.method())  # B的方法(按MRO顺序:D -> B -> C -> A)
菱形继承问题
典型的菱形继承结构:
     Person
    /      \
Student   Teacher
    \      /
TeachingAssistant
示例代码:
class Person:
    def __init__(self, name, **kwargs):
        super().__init__(**kwargs)  # 为未来多继承留接口
        self.name = name
        print(f"Person.__init__({name})")
class Student(Person):
    def __init__(self, student_id, **kwargs):
        super().__init__(**kwargs)
        self.student_id = student_id
        print(f"Student.__init__({student_id})")
class Teacher(Person):
    def __init__(self, subject, **kwargs):
        super().__init__(**kwargs)
        self.subject = subject
        print(f"Teacher.__init__({subject})")
class TeachingAssistant(Student, Teacher):
    def __init__(self, name, student_id, subject):
        super().__init__(name=name, student_id=student_id, subject=subject)
# 创建实例
ta = TeachingAssistant("张三", "S001", "Python")
print("\nMRO:", TeachingAssistant.__mro__)
print(f"\nta.name={ta.name}, ta.student_id={ta.student_id}, ta.subject={ta.subject}")
# 输出
Teacher.__init__(Python)
Student.__init__(S001)
Person.__init__(张三)
MRO: (<class '__main__.TeachingAssistant'>, <class '__main__.Student'>, <class '__main__.Teacher'>, <class '__main__.Person'>, <class 'object'>)
ta.name=张三, ta.student_id=S001, ta.subject=Python
# 注意:虽然 MRO 顺序是 Student 在 Teacher 前,但因为 Student.__init__ 调用了 super(),而 super() 在 Student 中指向 Teacher(根据 MRO),所以实际初始化顺序是 Teacher → Student → Person(从最右父类向左回溯)。
对比Java:
// Java不支持多继承,使用接口替代
public interface Flyable {
    void fly();
}
public interface Swimmable {
    void swim();
}
public class Duck implements Flyable, Swimmable {
    public void fly() {
        System.out.println("能飞");
    }
    public void swim() {
        System.out.println("能游泳");
    }
}
# 2.3、super()函数
super()用于调用父类的方法,在多继承中特别有用。
基本用法
class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
    def area(self):
        return self.width * self.height
class Square(Rectangle):
    def __init__(self, side):
        # 调用父类构造函数
        super().__init__(side, side)
    def perimeter(self):
        return 4 * self.width
square = Square(5)
print(square.area())       # 25
print(square.perimeter())  # 20
多继承中的super()
class Base:
    def __init__(self):
        print("Base初始化")
class A(Base):
    def __init__(self):
        print("A初始化开始")
        super().__init__()
        print("A初始化结束")
class B(Base):
    def __init__(self):
        print("B初始化开始")
        super().__init__()
        print("B初始化结束")
class C(A, B):
    def __init__(self):
        print("C初始化开始")
        super().__init__()  # 按MRO调用:C -> A -> B -> Base
        print("C初始化结束")
c = C()
# 输出:
# C初始化开始
# A初始化开始
# B初始化开始
# Base初始化
# B初始化结束
# A初始化结束
# C初始化结束
显式调用父类方法
class Animal:
    def speak(self):
        return "发出声音"
class Dog(Animal):
    def speak(self):
        # 调用父类方法
        parent_sound = super().speak()
        return f"{parent_sound} -> 汪汪汪!"
    def speak_like_parent(self):
        # 也可以直接通过类名调用
        return Animal.speak(self)
dog = Dog()
print(dog.speak())              # 发出声音 -> 汪汪汪!
print(dog.speak_like_parent())  # 发出声音
# 2.4、方法重写
子类可以重写(覆盖)父类的方法。
简单重写
class Employee:
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary
    def get_bonus(self):
        return self.salary * 0.1  # 基本奖金10%
class Manager(Employee):
    def __init__(self, name, salary, team_size):
        super().__init__(name, salary)
        self.team_size = team_size
    # 重写get_bonus方法
    def get_bonus(self):
        base_bonus = super().get_bonus()  # 获取基本奖金
        team_bonus = self.team_size * 1000  # 团队奖金
        return base_bonus + team_bonus
# 使用
employee = Employee("张三", 10000)
manager = Manager("李四", 15000, 5)
print(employee.get_bonus())  # 1000.0
print(manager.get_bonus())   # 6500.0(1500 + 5000)
重写特殊方法
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __str__(self):
        return f"{self.name},{self.age}岁"
    def __repr__(self):
        return f"Person('{self.name}', {self.age})"
class Student(Person):
    def __init__(self, name, age, grade):
        super().__init__(name, age)
        self.grade = grade
    # 重写__str__
    def __str__(self):
        parent_str = super().__str__()
        return f"{parent_str},{self.grade}年级"
    # 重写__repr__
    def __repr__(self):
        return f"Student('{self.name}', {self.age}, {self.grade})"
student = Student("张三", 18, 12)
print(str(student))   # 张三,18岁,12年级
print(repr(student))  # Student('张三', 18, 12)
# 2.5、多态性实现
Python的多态是"鸭子类型"(Duck Typing):如果对象行为像鸭子,就可以当鸭子用。
基于继承的多态
class Shape:
    def area(self):
        raise NotImplementedError("子类必须实现area方法")
    def perimeter(self):
        raise NotImplementedError("子类必须实现perimeter方法")
class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    def area(self):
        return self.width * self.height
    def perimeter(self):
        return 2 * (self.width + self.height)
class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    def area(self):
        return 3.14159 * self.radius ** 2
    def perimeter(self):
        return 2 * 3.14159 * self.radius
# 多态函数
def print_shape_info(shape):
    """接受任何Shape子类"""
    print(f"面积: {shape.area():.2f}")
    print(f"周长: {shape.perimeter():.2f}")
# 使用
rectangle = Rectangle(5, 3)
circle = Circle(4)
print_shape_info(rectangle)
print_shape_info(circle)
鸭子类型(Duck Typing)
# 不需要继承关系,只要有相同的方法就行
class Dog:
    def speak(self):
        return "汪汪汪"
class Cat:
    def speak(self):
        return "喵喵喵"
class Duck:
    def speak(self):
        return "嘎嘎嘎"
# 多态函数(不检查类型)
def make_animal_speak(animal):
    """只要有speak方法就行"""
    print(animal.speak())
# 使用
dog = Dog()
cat = Cat()
duck = Duck()
make_animal_speak(dog)   # 汪汪汪
make_animal_speak(cat)   # 喵喵喵
make_animal_speak(duck)  # 嘎嘎嘎
# 甚至可以传入任何有speak方法的对象
class Robot:
    def speak(self):
        return "哔哔哔"
make_animal_speak(Robot())  # 哔哔哔
对比Java:
// Java需要明确的继承或接口关系
public interface Animal {
    String speak();
}
public class Dog implements Animal {
    public String speak() {
        return "汪汪汪";
    }
}
public void makeAnimalSpeak(Animal animal) {
    // 必须是Animal类型
    System.out.println(animal.speak());
}
# 2.6、抽象基类(ABC模块)
如果想在Python中强制子类实现某些方法,可以使用抽象基类。
基本用法
from abc import ABC, abstractmethod
# 抽象基类
class Animal(ABC):
    def __init__(self, name):
        self.name = name
    @abstractmethod
    def speak(self):
        """子类必须实现"""
        pass
    @abstractmethod
    def move(self):
        """子类必须实现"""
        pass
    def info(self):
        """具体方法,子类可以直接使用"""
        return f"我是{self.name}"
# 具体实现
class Dog(Animal):
    def speak(self):
        return "汪汪汪"
    def move(self):
        return "跑动"
# 使用
# animal = Animal("动物")  # TypeError: 不能实例化抽象类
dog = Dog("旺财")
print(dog.speak())  # 汪汪汪
print(dog.move())   # 跑动
print(dog.info())   # 我是旺财
抽象属性
from abc import ABC, abstractmethod
class Shape(ABC):
    @property
    @abstractmethod
    def area(self):
        """抽象属性"""
        pass
    @property
    @abstractmethod
    def perimeter(self):
        """抽象属性"""
        pass
class Rectangle(Shape):
    def __init__(self, width, height):
        self._width = width
        self._height = height
    @property
    def area(self):
        return self._width * self._height
    @property
    def perimeter(self):
        return 2 * (self._width + self._height)
rect = Rectangle(5, 3)
print(rect.area)       # 15
print(rect.perimeter)  # 16
实际应用
from abc import ABC, abstractmethod
class DataProcessor(ABC):
    """数据处理抽象基类"""
    @abstractmethod
    def load_data(self, source):
        """加载数据"""
        pass
    @abstractmethod
    def process_data(self, data):
        """处理数据"""
        pass
    @abstractmethod
    def save_data(self, data, destination):
        """保存数据"""
        pass
    def run(self, source, destination):
        """模板方法(具体实现)"""
        print("开始处理...")
        data = self.load_data(source)
        processed = self.process_data(data)
        self.save_data(processed, destination)
        print("处理完成!")
class CSVProcessor(DataProcessor):
    def load_data(self, source):
        print(f"从CSV加载: {source}")
        return ["数据1", "数据2", "数据3"]
    def process_data(self, data):
        print("处理CSV数据...")
        return [item.upper() for item in data]
    def save_data(self, data, destination):
        print(f"保存到CSV: {destination}")
        print(f"数据: {data}")
# 使用
processor = CSVProcessor()
processor.run("input.csv", "output.csv")
对比Java:
// Java的抽象类
public abstract class Animal {
    private String name;
    public Animal(String name) {
        this.name = name;
    }
    // 抽象方法
    public abstract String speak();
    // 具体方法
    public String info() {
        return "我是" + name;
    }
}
public class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }
    @Override
    public String speak() {
        return "汪汪汪";
    }
}
小结对比表
| 特性 | Java | Python | 
|---|---|---|
| 单继承 | extends |  括号语法 (Parent) | 
| 多继承 | 不支持(用接口) | 支持多继承 | 
| 调用父类 | super.method() |  super().method() | 
| 方法重写 | @Override注解 |  直接重写(无需注解) | 
| 抽象类 | abstract class |  ABC+@abstractmethod | 
| 多态 | 基于类型 | 鸭子类型 | 
| MRO | 不适用 | C3线性化算法 | 
# 3、特殊方法(魔术方法)
Python的特殊方法(也叫魔术方法)是以双下划线开头和结尾的方法,它们让你的类能够使用Python的内置语法和运算符。这是Python面向对象编程的精髓之一。
# 3.1、对象表示:__str__和__repr__
 这两个方法控制对象如何被转换为字符串。
基本区别
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __str__(self):
        """用户友好的字符串表示(给人看的)"""
        return f"{self.name},{self.age}岁"
    def __repr__(self):
        """开发者友好的字符串表示(给程序员看的)"""
        return f"Person('{self.name}', {self.age})"
person = Person("张三", 25)
# __str__: 给最终用户看的
print(str(person))   # 张三,25岁
print(person)        # 张三,25岁(print会调用__str__)
# __repr__: 给开发者看的,应该是合法的Python表达式
print(repr(person))  # Person('张三', 25)
print([person])      # [Person('张三', 25)](容器会调用__repr__)
# 交互式环境中
>>> person
Person('张三', 25)  # 显示__repr__
最佳实践
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __repr__(self):
        """始终实现__repr__"""
        return f"Point({self.x}, {self.y})"
    def __str__(self):
        """可选实现__str__,如果不实现会使用__repr__"""
        return f"({self.x}, {self.y})"
# 只实现__repr__的类
class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __repr__(self):
        return f"Vector({self.x}, {self.y})"
    # 没有__str__,print时会使用__repr__
point = Point(3, 4)
vector = Vector(1, 2)
print(point)    # (3, 4) - 使用__str__
print(vector)   # Vector(1, 2) - 使用__repr__
print(repr(point))  # Point(3, 4)
对比Java:
// Java使用toString()
public class Person {
    private String name;
    private int age;
    @Override
    public String toString() {
        return name + "," + age + "岁";
    }
}
// 使用
Person person = new Person("张三", 25);
System.out.println(person);  // 张三,25岁
# 3.2、比较方法
Python提供了丰富的比较运算符重载方法。
基本比较方法
class Student:
    def __init__(self, name, score):
        self.name = name
        self.score = score
    def __eq__(self, other):
        """相等比较 =="""
        if not isinstance(other, Student):
            return False
        return self.score == other.score
    def __lt__(self, other):
        """小于比较 <"""
        if not isinstance(other, Student):
            return NotImplemented
        return self.score < other.score
    def __le__(self, other):
        """小于等于 <="""
        return self.score <= other.score
    def __gt__(self, other):
        """大于 >"""
        return self.score > other.score
    def __ge__(self, other):
        """大于等于 >="""
        return self.score >= other.score
    def __ne__(self, other):
        """不等于 !="""
        return not self.__eq__(other)
    def __repr__(self):
        return f"Student('{self.name}', {self.score})"
# 使用
student1 = Student("张三", 85)
student2 = Student("李四", 92)
student3 = Student("王五", 85)
print(student1 == student3)  # True(成绩相同)
print(student1 < student2)   # True
print(student1 <= student3)  # True
print(student2 > student1)   # True
# 可以用于排序
students = [student2, student1, student3]
sorted_students = sorted(students)
print(sorted_students)  # [Student('张三', 85), Student('王五', 85), Student('李四', 92)]
使用functools简化
from functools import total_ordering
@total_ordering
class Student:
    """只需实现__eq__和一个比较方法,自动生成其他"""
    def __init__(self, name, score):
        self.name = name
        self.score = score
    def __eq__(self, other):
        if not isinstance(other, Student):
            return NotImplemented
        return self.score == other.score
    def __lt__(self, other):
        if not isinstance(other, Student):
            return NotImplemented
        return self.score < other.score
    def __repr__(self):
        return f"Student('{self.name}', {self.score})"
# 自动拥有所有比较方法
student1 = Student("张三", 85)
student2 = Student("李四", 92)
print(student1 <= student2)  # True(自动生成)
print(student1 >= student2)  # False(自动生成)
# 3.3、容器方法
让你的类像列表、字典一样使用。
基本容器协议
class MyList:
    """自定义列表类"""
    def __init__(self, items=None):
        self._items = items or []
    def __len__(self):
        """len()函数调用"""
        return len(self._items)
    def __getitem__(self, index):
        """索引访问 obj[index]"""
        return self._items[index]
    def __setitem__(self, index, value):
        """索引赋值 obj[index] = value"""
        self._items[index] = value
    def __delitem__(self, index):
        """删除 del obj[index]"""
        del self._items[index]
    def __contains__(self, item):
        """成员检查 item in obj"""
        return item in self._items
    def __iter__(self):
        """迭代 for item in obj"""
        return iter(self._items)
    def __repr__(self):
        return f"MyList({self._items})"
# 使用
my_list = MyList([1, 2, 3, 4, 5])
print(len(my_list))        # 5
print(my_list[0])          # 1
my_list[0] = 10
print(my_list[0])          # 10
print(3 in my_list)        # True
for item in my_list:
    print(item, end=" ")   # 10 2 3 4 5
del my_list[0]
print(my_list)             # MyList([2, 3, 4, 5])
字典式访问
class Configuration:
    """配置类,支持字典式访问"""
    def __init__(self):
        self._config = {}
    def __getitem__(self, key):
        """config['key']"""
        return self._config[key]
    def __setitem__(self, key, value):
        """config['key'] = value"""
        self._config[key] = value
    def __delitem__(self, key):
        """del config['key']"""
        del self._config[key]
    def __contains__(self, key):
        """'key' in config"""
        return key in self._config
    def __len__(self):
        return len(self._config)
    def __repr__(self):
        return f"Configuration({self._config})"
# 使用
config = Configuration()
config['host'] = 'localhost'
config['port'] = 8080
print(config['host'])      # localhost
print('host' in config)    # True
print(len(config))         # 2
切片支持
class SmartList:
    def __init__(self, items):
        self._items = list(items)
    def __getitem__(self, key):
        """支持索引和切片"""
        if isinstance(key, slice):
            # 切片操作
            return SmartList(self._items[key])
        else:
            # 单个索引
            return self._items[key]
    def __len__(self):
        return len(self._items)
    def __repr__(self):
        return f"SmartList({self._items})"
# 使用
smart = SmartList([1, 2, 3, 4, 5])
print(smart[0])        # 1
print(smart[1:3])      # SmartList([2, 3])
print(smart[::2])      # SmartList([1, 3, 5])
# 3.4、可调用对象:__call__
 让对象可以像函数一样调用。
基本用法
class Multiplier:
    """乘法器,像函数一样使用"""
    def __init__(self, factor):
        self.factor = factor
    def __call__(self, x):
        """obj(x) 会调用这个方法"""
        return x * self.factor
# 使用
double = Multiplier(2)
triple = Multiplier(3)
print(double(5))    # 10
print(triple(5))    # 15
# 检查是否可调用
print(callable(double))  # True
实际应用:缓存装饰器
class Memoize:
    """缓存函数结果"""
    def __init__(self, func):
        self.func = func
        self.cache = {}
    def __call__(self, *args):
        if args not in self.cache:
            print(f"计算 {self.func.__name__}{args}")
            self.cache[args] = self.func(*args)
        else:
            print(f"从缓存获取 {args}")
        return self.cache[args]
@Memoize
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)
# 使用
print(fibonacci(5))
# 计算 fibonacci(5)
# 计算 fibonacci(4)
# ...
# 21
print(fibonacci(5))  # 从缓存获取 (5)
有状态的函数
class Counter:
    """计数器函数"""
    def __init__(self):
        self.count = 0
    def __call__(self):
        self.count += 1
        return self.count
counter = Counter()
print(counter())  # 1
print(counter())  # 2
print(counter())  # 3
print(counter.count)  # 3
# 3.5、上下文管理器简介
提示:上下文管理器的完整用法(包括
@contextmanager装饰器、ExitStack等)将在第8章"高级特性"中详细讲解。
基本概念
上下文管理器通过实现__enter__和__exit__方法,让对象能够配合with语句自动管理资源。
class SimpleFileManager:
    """简单文件管理器示例"""
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode
        self.file = None
    def __enter__(self):
        print(f"打开文件: {self.filename}")
        self.file = open(self.filename, self.mode)
        return self.file
    def __exit__(self, exc_type, exc_value, traceback):
        if self.file:
            print(f"关闭文件: {self.filename}")
            self.file.close()
        # 返回False表示不抑制异常
        return False
# 使用with语句自动管理资源
with SimpleFileManager('test.txt', 'w') as f:
    f.write('Hello, World!')
# 文件自动关闭
核心协议
__enter__(self):进入with块时调用,返回要赋值给as变量的对象__exit__(self, exc_type, exc_value, traceback):退出with块时调用,处理清理工作
# 4、特殊方法总结
下面是一个实用的特殊方法速查表:
| 方法 | 触发时机 | 示例 | 
|---|---|---|
__str__ |  print(obj) |  对象的可读字符串表示 | 
__repr__ |  repr(obj) |  对象的明确表示 | 
__len__ |  len(obj) |  返回对象长度 | 
__getitem__ |  obj[key] |  索引访问 | 
__setitem__ |  obj[key] = value |  索引赋值 | 
__call__ |  obj() |  对象可调用 | 
__enter__ |  with obj as f: |  进入上下文 | 
__exit__ |  退出with块 | 退出上下文 | 
对比Java:
// Java使用try-with-resources
public class FileManager implements AutoCloseable {
    private String filename;
    public FileManager(String filename) {
        this.filename = filename;
    }
    @Override
    public void close() {
        System.out.println("关闭文件: " + filename);
    }
}
// 使用
try (FileManager fm = new FileManager("test.txt")) {
    // 使用资源
} // 自动关闭
# 4.1、运算符重载
让自定义类支持各种运算符。
算术运算符
class Vector:
    """二维向量"""
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __add__(self, other):
        """加法 +"""
        return Vector(self.x + other.x, self.y + other.y)
    def __sub__(self, other):
        """减法 -"""
        return Vector(self.x - other.x, self.y - other.y)
    def __mul__(self, scalar):
        """乘法 *"""
        return Vector(self.x * scalar, self.y * scalar)
    def __truediv__(self, scalar):
        """除法 /"""
        return Vector(self.x / scalar, self.y / scalar)
    def __abs__(self):
        """绝对值 abs()"""
        return (self.x ** 2 + self.y ** 2) ** 0.5
    def __neg__(self):
        """取负 -obj"""
        return Vector(-self.x, -self.y)
    def __eq__(self, other):
        """相等 =="""
        return self.x == other.x and self.y == other.y
    def __repr__(self):
        return f"Vector({self.x}, {self.y})"
# 使用
v1 = Vector(2, 3)
v2 = Vector(1, 1)
print(v1 + v2)    # Vector(3, 4)
print(v1 - v2)    # Vector(1, 2)
print(v1 * 2)     # Vector(4, 6)
print(v1 / 2)     # Vector(1.0, 1.5)
print(abs(v1))    # 3.605551275463989
print(-v1)        # Vector(-2, -3)
print(v1 == v2)   # False
反向运算符
class Number:
    def __init__(self, value):
        self.value = value
    def __add__(self, other):
        """obj + other"""
        return Number(self.value + other)
    def __radd__(self, other):
        """other + obj(反向加法)"""
        return Number(other + self.value)
    def __mul__(self, other):
        """obj * other"""
        return Number(self.value * other)
    def __rmul__(self, other):
        """other * obj(反向乘法)"""
        return Number(other * self.value)
    def __repr__(self):
        return f"Number({self.value})"
# 使用
num = Number(5)
print(num + 3)    # Number(8) - 调用__add__
print(3 + num)    # Number(8) - 调用__radd__
print(num * 2)    # Number(10) - 调用__mul__
print(2 * num)    # Number(10) - 调用__rmul__
增强赋值运算符
class Counter:
    def __init__(self, value=0):
        self.value = value
    def __iadd__(self, other):
        """+="""
        self.value += other
        return self
    def __isub__(self, other):
        """-="""
        self.value -= other
        return self
    def __imul__(self, other):
        """*="""
        self.value *= other
        return self
    def __repr__(self):
        return f"Counter({self.value})"
# 使用
counter = Counter(10)
counter += 5
print(counter)    # Counter(15)
counter -= 3
print(counter)    # Counter(12)
counter *= 2
print(counter)    # Counter(24)
完整运算符列表
| 运算符 | 方法 | 说明 | 
|---|---|---|
+ |  __add__ |  加法 | 
- |  __sub__ |  减法 | 
* |  __mul__ |  乘法 | 
/ |  __truediv__ |  除法 | 
// |  __floordiv__ |  整除 | 
% |  __mod__ |  取模 | 
** |  __pow__ |  幂运算 | 
& |  __and__ |  按位与 | 
\| |  __or__ |  按位或 | 
^ |  __xor__ |  按位异或 | 
<< |  __lshift__ |  左移 | 
>> |  __rshift__ |  右移 | 
-obj |  __neg__ |  取负 | 
+obj |  __pos__ |  取正 | 
~obj |  __invert__ |  按位取反 | 
实际应用:货币类
class Money:
    """货币类,支持运算"""
    def __init__(self, amount, currency="CNY"):
        self.amount = amount
        self.currency = currency
    def __add__(self, other):
        if self.currency != other.currency:
            raise ValueError("不同币种不能相加")
        return Money(self.amount + other.amount, self.currency)
    def __sub__(self, other):
        if self.currency != other.currency:
            raise ValueError("不同币种不能相减")
        return Money(self.amount - other.amount, self.currency)
    def __mul__(self, factor):
        """乘以数字"""
        return Money(self.amount * factor, self.currency)
    def __truediv__(self, divisor):
        """除以数字"""
        return Money(self.amount / divisor, self.currency)
    def __eq__(self, other):
        return self.amount == other.amount and self.currency == other.currency
    def __lt__(self, other):
        if self.currency != other.currency:
            raise ValueError("不同币种不能比较")
        return self.amount < other.amount
    def __repr__(self):
        return f"{self.currency} {self.amount:.2f}"
# 使用
price1 = Money(100.50, "CNY")
price2 = Money(50.25, "CNY")
total = price1 + price2
print(total)              # CNY 150.75
discount = price1 * 0.8
print(discount)           # CNY 80.40
print(price1 > price2)    # True
# 4.2、其他常用特殊方法
__hash__:可哈希对象
class Person:
    def __init__(self, name, id_number):
        self.name = name
        self.id_number = id_number
    def __eq__(self, other):
        if not isinstance(other, Person):
            return False
        return self.id_number == other.id_number
    def __hash__(self):
        """使对象可以作为字典键和集合元素"""
        return hash(self.id_number)
    def __repr__(self):
        return f"Person('{self.name}', '{self.id_number}')"
# 使用
person1 = Person("张三", "123456")
person2 = Person("张三", "123456")
person3 = Person("李四", "789012")
# 可以作为字典键
people = {
    person1: "数据1",
    person3: "数据2"
}
# 可以放入集合
person_set = {person1, person2, person3}
print(len(person_set))  # 2(person1和person2被认为是同一个)
__bool__:真值测试
class Result:
    def __init__(self, data, error=None):
        self.data = data
        self.error = error
    def __bool__(self):
        """if result: 时调用"""
        return self.error is None
    def __repr__(self):
        if self.error:
            return f"Result(error={self.error})"
        return f"Result(data={self.data})"
# 使用
success = Result({"user": "张三"})
failure = Result(None, "连接失败")
if success:
    print("成功!")  # 输出
if not failure:
    print("失败!")  # 输出
__format__:格式化输出
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __format__(self, format_spec):
        """format(obj, spec) 时调用"""
        if format_spec == 'p':
            return f"({self.x}, {self.y})"
        elif format_spec == 'c':
            return f"{self.x}+{self.y}i"
        else:
            return f"Point({self.x}, {self.y})"
# 使用
point = Point(3, 4)
print(f"{point}")      # Point(3, 4)
print(f"{point:p}")    # (3, 4)
print(f"{point:c}")    # 3+4i
小结对比表
| 特殊方法 | 用途 | Java对应 | 
|---|---|---|
__str__ |  字符串表示 | toString() | 
__repr__ |  开发者表示 | 无直接对应 | 
__eq__ |  相等比较 | equals() | 
__hash__ |  哈希值 | hashCode() | 
__len__ |  长度 | size() | 
__getitem__ |  索引访问 | get() | 
__call__ |  可调用 | 函数式接口 | 
__enter__/__exit__ |  上下文管理 | AutoCloseable | 
__add__ |  加法 | 无(不支持运算符重载) | 
Python的特殊方法让你的类能够无缝融入Python的语法体系,写出更Pythonic的代码!
# 5、Python数据类
Python 3.7引入的dataclass装饰器大大简化了数据类的定义,类似于Java 14+的record类。
# 5.1、基本用法
不使用dataclass的传统写法
# 传统写法:需要大量样板代码
class Person:
    def __init__(self, name, age, city):
        self.name = name
        self.age = age
        self.city = city
    def __repr__(self):
        return f"Person(name={self.name!r}, age={self.age!r}, city={self.city!r})"
    def __eq__(self, other):
        if not isinstance(other, Person):
            return NotImplemented
        return (self.name, self.age, self.city) == (other.name, other.age, other.city)
使用dataclass
from dataclasses import dataclass
@dataclass
class Person:
    name: str
    age: int
    city: str
# 自动生成__init__、__repr__、__eq__等方法
person = Person("张三", 25, "北京")
print(person)  # Person(name='张三', age=25, city='北京')
person2 = Person("张三", 25, "北京")
print(person == person2)  # True
对比Java Record:
// Java 14+ Record
public record Person(String name, int age, String city) {}
// 使用
Person person = new Person("张三", 25, "北京");
System.out.println(person);  // Person[name=张三, age=25, city=北京]
# 5.2、字段定义与默认值
默认值
from dataclasses import dataclass
@dataclass
class User:
    username: str
    email: str
    is_active: bool = True      # 默认值
    role: str = "user"
    login_count: int = 0
# 使用
user1 = User("张三", "zhang@example.com")
print(user1)
# User(username='张三', email='zhang@example.com', is_active=True, role='user', login_count=0)
user2 = User("李四", "li@example.com", is_active=False, role="admin")
print(user2)
# User(username='李四', email='li@example.com', is_active=False, role='admin', login_count=0)
默认工厂函数
from dataclasses import dataclass, field
from typing import List
from datetime import datetime
@dataclass
class BlogPost:
    title: str
    content: str
    tags: List[str] = field(default_factory=list)  # 使用工厂函数
    created_at: datetime = field(default_factory=datetime.now)
    view_count: int = 0
# 使用
post1 = BlogPost("Python教程", "这是内容")
post2 = BlogPost("Java教程", "另一个内容", tags=["Java", "编程"])
print(post1.tags)       # []
print(post2.tags)       # ['Java', '编程']
print(post1.created_at) # 当前时间
# 注意:不要这样写(错误)
# tags: List[str] = []  # ❌ 所有实例共享同一个列表!
字段元数据
from dataclasses import dataclass, field
@dataclass
class Product:
    name: str
    price: float
    stock: int = field(default=0, metadata={"unit": "件"})
    description: str = field(default="", repr=False)  # 不在repr中显示
    _internal_id: int = field(default=0, init=False, repr=False)  # 不在__init__中
# 使用
product = Product("笔记本电脑", 5999.00, 10)
print(product)
# Product(name='笔记本电脑', price=5999.0, stock=10)
# 访问元数据
from dataclasses import fields
for f in fields(Product):
    if f.metadata:
        print(f"{f.name}: {f.metadata}")
# stock: {'unit': '件'}
# 5.3、自动生成的特殊方法
可配置的方法生成
from dataclasses import dataclass
# 完整配置
@dataclass(
    init=True,        # 生成__init__(默认True)
    repr=True,        # 生成__repr__(默认True)
    eq=True,          # 生成__eq__(默认True)
    order=False,      # 生成比较方法__lt__等(默认False)
    frozen=False,     # 不可变(默认False)
    unsafe_hash=False # 生成__hash__(默认False)
)
class Point:
    x: int
    y: int
# 不可变数据类
@dataclass(frozen=True)
class ImmutablePoint:
    x: int
    y: int
point = ImmutablePoint(3, 4)
# point.x = 5  # FrozenInstanceError
# 可比较的数据类
@dataclass(order=True)
class Student:
    name: str
    score: int
students = [Student("张三", 85), Student("李四", 92), Student("王五", 78)]
sorted_students = sorted(students)
print([s.name for s in sorted_students])  # ['张三', '李四', '王五']
自定义__post_init__
from dataclasses import dataclass
@dataclass
class Rectangle:
    width: float
    height: float
    area: float = None  # 计算属性
    def __post_init__(self):
        """在__init__之后自动调用"""
        if self.area is None:
            self.area = self.width * self.height
        # 验证
        if self.width <= 0 or self.height <= 0:
            raise ValueError("宽度和高度必须大于0")
# 使用
rect = Rectangle(5, 3)
print(rect.area)  # 15.0
# rect = Rectangle(-5, 3)  # ValueError
init-only字段
from dataclasses import dataclass, field, InitVar
@dataclass
class User:
    username: str
    password_hash: str = field(init=False, repr=False)
    password: InitVar[str] = None  # 仅在__init__中使用
    def __post_init__(self, password):
        """password只在初始化时存在"""
        if password:
            self.password_hash = hash(password)  # 简化示例
# 使用
user = User("张三", password="secret123")
print(user)  # User(username='张三')
# user.password  # AttributeError(不存在)
print(user.password_hash)  # 哈希值
# 5.4、继承与组合
数据类继承
from dataclasses import dataclass
@dataclass
class Person:
    name: str
    age: int
@dataclass
class Employee(Person):
    employee_id: str
    department: str
# 使用
emp = Employee("张三", 30, "E001", "技术部")
print(emp)
# Employee(name='张三', age=30, employee_id='E001', department='技术部')
组合模式
from dataclasses import dataclass
from typing import List
@dataclass
class Address:
    street: str
    city: str
    country: str = "中国"
@dataclass
class Contact:
    email: str
    phone: str
@dataclass
class Company:
    name: str
    address: Address
    contacts: List[Contact]
    employee_count: int = 0
# 使用
address = Address("中关村大街1号", "北京")
contacts = [
    Contact("hr@company.com", "010-12345678"),
    Contact("sales@company.com", "010-87654321")
]
company = Company("科技公司", address, contacts, 500)
print(company.address.city)  # 北京
print(company.contacts[0].email)  # hr@company.com
# 5.5、高级特性
字段转换
from dataclasses import dataclass, field, asdict, astuple
@dataclass
class Book:
    title: str
    author: str
    price: float
    tags: list = field(default_factory=list)
book = Book("Python编程", "作者", 59.9, ["编程", "Python"])
# 转换为字典
book_dict = asdict(book)
print(book_dict)
# {'title': 'Python编程', 'author': '作者', 'price': 59.9, 'tags': ['编程', 'Python']}
# 转换为元组
book_tuple = astuple(book)
print(book_tuple)
# ('Python编程', '作者', 59.9, ['编程', 'Python'])
替换字段值
from dataclasses import dataclass, replace
@dataclass(frozen=True)
class Point:
    x: int
    y: int
point1 = Point(3, 4)
point2 = replace(point1, x=5)  # 创建新对象
print(point1)  # Point(x=3, y=4)
print(point2)  # Point(x=5, y=4)
实际应用:配置类
from dataclasses import dataclass, field
from typing import Optional
import json
@dataclass
class DatabaseConfig:
    host: str = "localhost"
    port: int = 5432
    database: str = "mydb"
    username: str = "admin"
    password: str = field(default="", repr=False)  # 不显示密码
    pool_size: int = 10
    timeout: int = 30
    ssl: bool = False
    def to_json(self) -> str:
        """导出为JSON"""
        from dataclasses import asdict
        return json.dumps(asdict(self), indent=2)
    @classmethod
    def from_json(cls, json_str: str):
        """从JSON创建"""
        data = json.loads(json_str)
        return cls(**data)
# 使用
config = DatabaseConfig(
    host="prod-db.example.com",
    database="production",
    username="prod_user",
    password="secret",
    ssl=True
)
print(config)
# DatabaseConfig(host='prod-db.example.com', port=5432, database='production',
#                username='prod_user', pool_size=10, timeout=30, ssl=True)
# 序列化
json_str = config.to_json()
print(json_str)
# 反序列化
config2 = DatabaseConfig.from_json(json_str)
# 5.6、与普通类和namedtuple对比
对比表
| 特性 | 普通类 | namedtuple | dataclass | 
|---|---|---|---|
| 定义简洁度 | ❌ 冗长 | ✅ 简洁 | ✅ 简洁 | 
| 可变性 | ✅ 可变 | ❌ 不可变 | ✅ 可配置 | 
| 类型注解 | ❌ 手动 | ❌ 无 | ✅ 内置 | 
| 默认值 | ✅ 支持 | ❌ 不支持 | ✅ 支持 | 
| 继承 | ✅ 支持 | ⚠️ 复杂 | ✅ 支持 | 
| 方法 | ✅ 支持 | ✅ 支持 | ✅ 支持 | 
| 性能 | ✅ 好 | ✅ 好 | ✅ 好 | 
示例对比
# 1. 普通类(最灵活,最冗长)
class PersonClass:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __repr__(self):
        return f"Person(name={self.name!r}, age={self.age!r})"
    def __eq__(self, other):
        if not isinstance(other, PersonClass):
            return NotImplemented
        return (self.name, self.age) == (other.name, other.age)
# 2. namedtuple(简洁,不可变)
from collections import namedtuple
PersonTuple = namedtuple('Person', ['name', 'age'])
# 3. dataclass(最佳平衡)
from dataclasses import dataclass
@dataclass
class PersonData:
    name: str
    age: int
# 使用对比
p1 = PersonClass("张三", 25)
p2 = PersonTuple("张三", 25)
p3 = PersonData("张三", 25)
# 可变性
p1.age = 26  # ✅
# p2.age = 26  # ❌ AttributeError
p3.age = 26  # ✅
# 类型提示
# PersonClass: 无类型信息
# PersonTuple: 无类型信息
# PersonData: 完整类型注解
小结对比表
| 特性 | Python dataclass | Java record | 
|---|---|---|
| 引入版本 | Python 3.7 | Java 14 | 
| 可变性 | 默认可变,可配置 | 不可变 | 
| 默认值 | 支持 | 不支持 | 
| 继承 | 支持 | 不支持(可实现接口) | 
| 生成方法 | 可配置 | 自动生成全部 | 
| 序列化 | 需手动 | 自动支持 | 
Python的数据类比Java的record更灵活,但两者都大大减少了数据承载类的样板代码!
# 6、特殊内置变量
Python中有大量以双下划线开头和结尾的特殊内置变量,它们由解释器自动设置,提供了丰富的运行时元信息。理解这些变量对于深入掌握Python至关重要。
区别:特殊内置变量是变量(存储值),魔术方法是方法(定义行为)
# 6.1、模块级别的特殊变量
__name__:模块名称
# my_module.py
print(f"模块名: {__name__}")
def main():
    print("执行主程序")
if __name__ == "__main__":
    # 只有直接运行时才执行
    main()
# 直接运行
$ python my_module.py
# 输出: 模块名: __main__
#       执行主程序
# 作为模块导入
>>> import my_module
# 输出: 模块名: my_module
# main()不会执行
对比Java:
// Java用main方法作为入口
public class MyClass {
    public static void main(String[] args) {
        System.out.println("执行主程序");
    }
}
__file__:文件路径
# utils.py
import os
print(f"文件路径: {__file__}")
print(f"绝对路径: {os.path.abspath(__file__)}")
print(f"所在目录: {os.path.dirname(__file__)}")
# 输出:
# 文件路径: /path/to/utils.py
# 绝对路径: /path/to/utils.py
# 所在目录: /path/to
实际应用:
# 读取同目录下的配置文件
import os
import json
# 获取当前脚本所在目录
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
CONFIG_FILE = os.path.join(CURRENT_DIR, 'config.json')
with open(CONFIG_FILE) as f:
    config = json.load(f)
__doc__:文档字符串
"""
这是模块的文档字符串
用于描述模块功能
"""
def greet(name):
    """返回问候语"""
    return f"Hello, {name}"
class Person:
    """人类"""
    def __init__(self, name):
        """初始化Person对象"""
        self.name = name
# 访问文档
print(__doc__)           # 模块文档
print(greet.__doc__)     # 函数文档
print(Person.__doc__)    # 类文档
print(Person.__init__.__doc__)  # 方法文档
__package__:包名
# mypackage/submodule.py
print(f"包名: {__package__}")        # mypackage
print(f"模块名: {__name__}")         # mypackage.submodule
# 用于相对导入
from . import other_module          # 同级模块
from .. import parent_module        # 上级模块
其他模块级变量
# 查看所有模块级特殊变量
import sys
print(f"__cached__: {__cached__}")    # .pyc文件路径
print(f"__spec__: {__spec__}")        # 模块规范对象
print(f"__loader__: {__loader__}")    # 模块加载器
# __builtins__: 内置函数和异常
print(type(__builtins__))             # <class 'module'>
# 6.2、类级别的特殊变量
__class__:对象的类
class Person:
    def __init__(self, name):
        self.name = name
person = Person("张三")
# 获取类
print(person.__class__)              # <class '__main__.Person'>
print(type(person))                  # <class '__main__.Person'>(等价)
# 判断类型
print(person.__class__.__name__)     # Person
# 通过类创建新实例
another = person.__class__("李四")
print(another.name)                  # 李四
__dict__:属性字典
class User:
    class_var = "类变量"
    def __init__(self, username, age):
        self.username = username
        self.age = age
user = User("张三", 25)
# 实例属性字典
print(user.__dict__)
# {'username': '张三', 'age': 25}
# 类属性字典
print(User.__dict__)
# {..., 'class_var': '类变量', '__init__': <function>, ...}
# 动态添加属性
user.__dict__['email'] = 'zhang@example.com'
print(user.email)  # zhang@example.com
# 查看所有属性
for key, value in user.__dict__.items():
    print(f"{key}: {value}")
对比Java:
// Java使用反射访问字段
import java.lang.reflect.Field;
Field[] fields = user.getClass().getDeclaredFields();
for (Field field : fields) {
    field.setAccessible(true);
    System.out.println(field.getName() + ": " + field.get(user));
}
__module__:类所在模块
# mypackage/models.py
class User:
    pass
user = User()
print(user.__class__.__module__)  # mypackage.models
print(User.__module__)            # mypackage.models
__bases__:直接父类
class Animal:
    pass
class Mammal(Animal):
    pass
class Dog(Mammal):
    pass
# 查看直接父类
print(Dog.__bases__)              # (<class '__main__.Mammal'>,)
print(Mammal.__bases__)           # (<class '__main__.Animal'>,)
print(Animal.__bases__)           # (<class 'object'>,)
# 多继承
class Flyable:
    pass
class Bird(Animal, Flyable):
    pass
print(Bird.__bases__)             # (<class '__main__.Animal'>, <class '__main__.Flyable'>)
__mro__:方法解析顺序
class A:
    pass
class B(A):
    pass
class C(A):
    pass
class D(B, C):
    pass
# MRO(C3线性化)
print(D.__mro__)
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>,
#  <class '__main__.A'>, <class 'object'>)
# 也可以用mro()方法
print(D.mro())
__qualname__:限定名称
class Outer:
    class Inner:
        def method(self):
            pass
print(Outer.__name__)                    # Outer
print(Outer.__qualname__)                # Outer
print(Outer.Inner.__name__)              # Inner
print(Outer.Inner.__qualname__)          # Outer.Inner
print(Outer.Inner.method.__name__)       # method
print(Outer.Inner.method.__qualname__)   # Outer.Inner.method
# 6.3、函数级别的特殊变量
函数属性
def greet(name: str, age: int = 18) -> str:
    """返回问候语"""
    return f"Hello, {name}! You are {age} years old."
# 函数名称
print(greet.__name__)                    # greet
# 文档字符串
print(greet.__doc__)                     # 返回问候语
# 所在模块
print(greet.__module__)                  # __main__
# 类型注解
print(greet.__annotations__)
# {'name': <class 'str'>, 'age': <class 'int'>, 'return': <class 'str'>}
# 默认参数值
print(greet.__defaults__)                # (18,)
# 代码对象
print(greet.__code__)                    # <code object greet at ...>
print(greet.__code__.co_varnames)        # ('name', 'age')
print(greet.__code__.co_argcount)        # 2
闭包变量
def outer(x):
    y = 10
    def inner(z):
        return x + y + z
    return inner
closure = outer(5)
# 闭包变量
print(closure.__closure__)
# (<cell at 0x...: int object at 0x...>, <cell at 0x...: int object at 0x...>)
# 查看闭包捕获的变量
for cell in closure.__closure__:
    print(cell.cell_contents)  # 5, 10
# 6.4、其他重要特殊变量
__debug__:调试模式
# 默认为True
print(__debug__)  # True
# 使用-O优化模式运行时为False
# python -O script.py
# 用于条件调试代码
if __debug__:
    print("调试信息:变量值为", x)
__all__:公开接口
# mymodule.py
__all__ = ['public_func', 'PublicClass']
def public_func():
    """公开函数"""
    pass
def _internal_func():
    """内部函数"""
    pass
class PublicClass:
    """公开类"""
    pass
class _InternalClass:
    """内部类"""
    pass
# 使用from import *时,只导入__all__中的内容
from mymodule import *
public_func()      # ✅ 可用
# _internal_func() # ❌ NameError
__slots__:限制属性
class Point:
    """限制只能有x和y属性"""
    __slots__ = ['x', 'y']
    def __init__(self, x, y):
        self.x = x
        self.y = y
point = Point(3, 4)
print(point.x, point.y)  # 3 4
# 不能添加新属性
# point.z = 5  # AttributeError
# 没有__dict__(节省内存)
# print(point.__dict__)  # AttributeError
优势:
- 节省内存(没有
__dict__) - 更快的属性访问
 - 防止属性拼写错误
 
__annotations__:类型注解
class User:
    name: str
    age: int
    email: str = "未设置"
    def __init__(self, name: str, age: int):
        self.name = name
        self.age = age
# 查看类型注解
print(User.__annotations__)
# {'name': <class 'str'>, 'age': <class 'int'>, 'email': <class 'str'>}
# 函数的类型注解
def process(data: list[int]) -> int:
    return sum(data)
print(process.__annotations__)
# {'data': list[int], 'return': <class 'int'>}
# 6.5、实用工具函数
dir():列出所有属性
class Person:
    def __init__(self, name):
        self.name = name
    def greet(self):
        pass
person = Person("张三")
# 列出所有属性和方法
print(dir(person))
# ['__class__', '__delattr__', ..., 'greet', 'name', ...]
# 只列出特殊变量/方法
special = [x for x in dir(person) if x.startswith('__') and x.endswith('__')]
print(special)
vars():返回__dict__
user = User("张三", 25)
# 等同于user.__dict__
print(vars(user))
# {'name': '张三', 'age': 25}
# 修改属性
vars(user)['age'] = 26
print(user.age)  # 26
getattr()、setattr()、hasattr()
class Config:
    debug = True
    port = 8080
config = Config()
# 获取属性
debug = getattr(config, 'debug')          # True
timeout = getattr(config, 'timeout', 30)  # 30(默认值)
# 设置属性
setattr(config, 'host', 'localhost')
print(config.host)  # localhost
# 检查属性
print(hasattr(config, 'debug'))    # True
print(hasattr(config, 'timeout'))  # False
# 动态操作
attr_name = 'port'
value = getattr(config, attr_name)
print(value)  # 8080
# 6.6、实际应用案例
案例1:对象序列化
class Person:
    def __init__(self, name, age, city):
        self.name = name
        self.age = age
        self.city = city
    def to_dict(self):
        """转换为字典"""
        return self.__dict__.copy()
    @classmethod
    def from_dict(cls, data):
        """从字典创建对象"""
        return cls(**data)
# 使用
person = Person("张三", 25, "北京")
data = person.to_dict()
print(data)  # {'name': '张三', 'age': 25, 'city': '北京'}
# 反序列化
person2 = Person.from_dict(data)
print(person2.name)  # 张三
案例2:插件系统
class PluginBase:
    """插件基类"""
    pass
class Plugin1(PluginBase):
    pass
class Plugin2(PluginBase):
    pass
# 自动发现所有插件
def discover_plugins():
    """获取所有插件类"""
    plugins = []
    for cls in PluginBase.__subclasses__():
        plugins.append(cls)
    return plugins
print(discover_plugins())
# [<class '__main__.Plugin1'>, <class '__main__.Plugin2'>]
案例3:调试信息
def debug_info(obj):
    """打印对象的调试信息"""
    print(f"类型: {obj.__class__.__name__}")
    print(f"模块: {obj.__class__.__module__}")
    print(f"MRO: {[c.__name__ for c in obj.__class__.__mro__]}")
    print(f"属性: {obj.__dict__}")
class User:
    def __init__(self, name):
        self.name = name
user = User("张三")
debug_info(user)
# 类型: User
# 模块: __main__
# MRO: ['User', 'object']
# 属性: {'name': '张三'}
小结对比表
| 变量类型 | Python特殊变量 | Java对应 | 
|---|---|---|
| 模块名 | __name__ |  无(用main方法) | 
| 文件路径 | __file__ |  无直接对应 | 
| 类信息 | __class__, __bases__ |  getClass(), getSuperclass() | 
| 属性字典 | __dict__ |  反射API | 
| MRO | __mro__ |  无(单继承) | 
| 文档 | __doc__ |  JavaDoc注释 | 
| 类型注解 | __annotations__ |  类型声明 | 
记忆技巧:
- 模块相关:
__name__、__file__、__package__ - 类相关:
__class__、__bases__、__mro__、__module__ - 属性相关:
__dict__、__slots__、__annotations__ - 元信息:
__doc__、__qualname__、__all__ 
📖 系列文章导航
本文是"Java开发者转战Python"系列的第一篇,全面介绍Python的基础知识。
📚 系列:
祝你变得更强!