轩辕李的博客 轩辕李的博客
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • HTML&CSS
  • JavaScript
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

轩辕李

勇猛精进,星辰大海
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • HTML&CSS
  • JavaScript
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Java

  • Spring

  • 其他语言

    • C语言指针二三事
    • 从Java到Kotlin
    • Groovy语言探索
    • Java开发者转战Python:基础篇
      • 一、Python简介与环境搭建
        • 1、Python的发展历程与特点
        • 1.1、Python的历史演进
        • 1.2、3的重大改进
        • 1.3、Python的设计哲学
        • 1.4、Python的核心优势
        • 2、Python与Java的核心差异
        • 2.1、运行机制差异
        • 2.2、类型系统差异
        • 2.3、性能与内存管理
        • 2.4、代码组织与语法风格
        • 3、Python环境搭建
        • 3.1、Python安装
        • 3.2、虚拟环境管理
        • 3.3、IDE与编辑器选择
        • 3.4、pip包管理器
      • 二、Python基础语法
        • 1、变量与数据类型
        • 1.1、变量声明与命名规范
        • 1.2、基本数据类型
        • 1.3、类型转换与类型检查
        • 1.4、与Java的类型系统对比
        • 2、字符串操作
        • 2.1、字符串定义方式
        • 2.2、字符串格式化
        • 2.3、常用字符串方法
        • 2.4、字符串切片操作
        • 2.5、原始字符串与转义字符
        • 2.6、字符串性能提示
        • 3、运算符
        • 3.1、算术运算符
        • 3.2、比较运算符
        • 3.3、逻辑运算符
        • 3.4、位运算符
        • 3.5、成员运算符(Python独有)
        • 3.6、身份运算符(Python独有)
        • 3.7、运算符优先级
        • 4、控制流
        • 4.1、if-elif-else条件语句
        • 4.2、while循环
        • 4.3、for循环与迭代器
        • 4.4、range()函数
        • 4.5、break、continue、pass
        • 4.6、循环中的else子句
        • 4.7、嵌套循环与性能优化
        • 4.8、实用的控制流技巧
        • 5、数据结构与推导式
        • 5.1、列表(list)
        • 5.2、元组(tuple)
        • a、命名元组(namedtuple)
        • 5.3、字典(dict)
        • 5.4、集合(set)
        • 5.5、与Java集合框架对比
        • 6、函数定义与使用
        • 6.1、函数定义语法
        • 6.2、参数传递
        • 6.3、返回值与多返回值
        • 6.4、函数作为一等公民
        • 6.5、lambda表达式
        • 6.6、作用域与LEGB规则
        • 6.7、闭包
        • 7、模块与包
        • 7.1、模块导入方式
        • 7.2、模块搜索路径
        • 7.3、__name__变量与入口点
        • 7.4、包的组织结构
        • 7.5、__init__.py文件的作用
        • 7.6、相对导入与绝对导入
        • 7.7、实际项目结构示例
        • 7.8、第三方包管理
      • 三、面向对象编程
        • 1、类与对象
        • 1.1、类的定义
        • 1.2、构造函数(__init__)
        • 1.3、实例属性与类属性
        • 1.4、实例方法、类方法、静态方法
        • 1.5、私有属性与方法
        • 1.6、属性访问器(property装饰器)
        • 2、继承与多态
        • 2.1、单继承
        • 2.2、多继承与MRO(方法解析顺序)
        • 2.3、super()函数
        • 2.4、方法重写
        • 2.5、多态性实现
        • 2.6、抽象基类(ABC模块)
        • 3、特殊方法(魔术方法)
        • 3.1、对象表示:__str__和__repr__
        • 3.2、比较方法
        • 3.3、容器方法
        • 3.4、可调用对象:__call__
        • 3.5、上下文管理器简介
        • 4、特殊方法总结
        • 4.1、运算符重载
        • 4.2、其他常用特殊方法
        • 5、Python数据类
        • 5.1、基本用法
        • 5.2、字段定义与默认值
        • 5.3、自动生成的特殊方法
        • 5.4、继承与组合
        • 5.5、高级特性
        • 5.6、与普通类和namedtuple对比
        • 6、特殊内置变量
        • 6.1、模块级别的特殊变量
        • 6.2、类级别的特殊变量
        • 6.3、函数级别的特殊变量
        • 6.4、其他重要特殊变量
        • 6.5、实用工具函数
        • 6.6、实际应用案例
    • Java开发者转战Python:进阶篇
    • Java开发者转战Python:热门库与质量管理
  • 工具

  • 后端
  • 其他语言
轩辕李
2025-01-13
目录

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的核心优势

  1. 简洁易读的语法:用缩进代替花括号,代码结构一目了然。习惯了Java的你可能一开始不适应,但很快就会爱上这种清爽的感觉

  2. 丰富的标准库和第三方生态:Python自带"电池"(batteries included),标准库几乎覆盖了日常开发的各个方面。再加上PyPI(Python Package Index)上50万+的第三方包,你几乎总能找到现成的轮子

  3. 动态类型与解释执行:无需编译,写完即跑。这对快速原型开发和脚本编写特别友好。当然,你也可以用类型注解+静态检查工具来获得类型安全

  4. 跨平台兼容性:写一次,到处运行——这次是真的。不像Java还需要考虑不同JVM的差异,Python的跨平台能力更加彻底

  5. 多范式编程支持:面向对象、函数式、过程式——想怎么写就怎么写。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的"慢"往往没想象中那么严重,因为:

  1. 性能瓶颈通常在I/O而非CPU
  2. 可以用C扩展加速关键代码(NumPy、Pandas底层都是C)
  3. 开发效率的提升能弥补运行效率的损失

内存管理机制

// 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安装

  1. 访问 python.org (opens new window) 下载Windows安装包
  2. 重要:安装时勾选"Add Python to PATH",这样就不用手动配置环境变量了
  3. 建议选择"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环境搭建成功!

小贴士:

  1. 建议每个项目都用独立的虚拟环境
  2. requirements.txt要纳入版本控制
  3. 定期更新pip本身:python -m pip install --upgrade pip
  4. 如果网络不稳定,可以考虑使用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
类型检查时机 编译期 运行期(可用工具静态检查)

实战建议:

  1. 小脚本可以不写类型注解,追求快速开发
  2. 大项目建议加上类型注解,配合mypy检查
  3. 利用Python的"鸭子类型",关注对象行为而非类型
  4. 善用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的基础知识。

📚 系列:

  • 进阶篇 - 异常处理、文件操作、装饰器、异步编程
  • 热门库与质量管理 - Python生态、质量管理

祝你变得更强!

编辑 (opens new window)
#Python
上次更新: 2025/11/03
Groovy语言探索
Java开发者转战Python:进阶篇

← Groovy语言探索 Java开发者转战Python:进阶篇→

最近更新
01
AI编程时代的一些心得
09-11
02
Claude Code与Codex的协同工作
09-01
03
Claude Code实战之供应商切换工具
08-18
更多文章>
Theme by Vdoing | Copyright © 2018-2025 京ICP备2021021832号-2 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式