Files
PythonLearn/03_面向对象/3_1_Python与Java的类和对象/README.md

8.6 KiB
Raw Blame History

第 3-1 课Python 与 Java 的类和对象

一、本课定位

你已经有成熟的 Java 开发经验,因此本阶段不再从“什么是对象”开始长篇讲解。本课采用差异驱动方式:先建立 Java 写法与 Python 写法的对应关系,再通过代码和练习形成 Python 语感。

即使没有完整阅读本文,也请至少运行示例并完成 practice.py。示例输出和练习题中会重复本课的关键差异。

二、本课目标

完成本课后,你将能够:

  1. 使用 Python 定义类、初始化对象并调用实例方法;
  2. 理解 self 与 Java this 的关系和语法差异;
  3. 区分实例属性与类属性;
  4. 区分实例方法、类方法和静态方法;
  5. 避免把 Java 的字段声明、构造器和 new 原样搬到 Python
  6. 理解 Python 对象模型更动态,但工程代码仍应保持清晰约束。

三、前置知识

  • 已有 Java 类、对象、构造器、实例字段和 static 成员经验;
  • 已学习 Python 函数、字典和类型注解;
  • 能在 PowerShell 中运行 Python 文件。

四、先看差异速查表

关注点 Java Python
定义类 public class Agent class Agent:
创建对象 new Agent(...) Agent(...),没有 new
初始化入口 与类同名的构造器 __init__ 特殊方法
当前对象 隐式 this 定义方法时显式写 self
实例字段 通常在类体中声明 通常在 __init__ 中赋值创建
类级数据 static 字段 类属性
实例方法 默认接收隐式 this 第一个参数通常写 self
类级工厂 常用 static 方法 常用 @classmethodcls
静态工具方法 static 方法 @staticmethod,无 self/cls
访问控制 public/protected/private 主要依赖命名约定,后续课详讲
方法重载 支持同名不同参数 不按 Java 方式支持,后续课详讲

五、最小类定义

class Agent:
    def __init__(self, name: str) -> None:
        self.name = name

    def describe(self) -> str:
        return f"Agent{self.name}"


agent = Agent("代码助手")
print(agent.describe())

对应 Java 思维可以理解为:

  • __init__ 负责接收初始化数据,但它不是与类同名的构造器;
  • self.name = name 在当前实例上创建并赋值 name 属性;
  • self 类似 this,只是 Python 要在方法定义中明确写出来;
  • 调用 agent.describe() 时不传 self,解释器会自动传入 agent
  • 创建对象直接调用 Agent(...),不写 new

严格来说Python 先通过 __new__ 创建对象,再由 __init__ 初始化对象。本阶段日常业务代码先掌握 __init__ 即可,暂不展开 __new__

六、Python 属性不要求预先声明

Java 通常先声明字段:

private String name;

Python 常在 __init__ 中直接建立实例属性:

self.name = name

Python 甚至允许对象创建后动态添加属性:

agent.status = "工作中"

这体现了 Python 的动态性。它不是鼓励随意改变对象结构;在成熟项目中,仍应尽量在 __init__ 中集中建立稳定的实例属性,让阅读者和类型检查工具更容易理解对象。

七、实例属性与类属性

class Agent:
    platform = "Codex"

    def __init__(self, name: str) -> None:
        self.name = name
  • self.name 是实例属性,每个对象可以保存不同值;
  • Agent.platform 是类属性,由类统一提供,作用类似 Java static 字段;
  • agent.platform 也能读取类属性,但类级含义明确时优先使用 Agent.platform
  • 如果执行 agent.platform = "其他平台",通常会在该实例上创建同名实例属性,从而遮蔽类属性,而不是修改整个类的值。

最后一点与 Java 字段访问直觉不同,是常见问题。

八、三种方法

8.1 实例方法

def describe(self) -> str:
    return self.name

通过 self 访问当前对象,适合处理实例状态。

8.2 类方法

@classmethod
def from_config(cls, config: dict[str, str]) -> "Agent":
    return cls(config["name"])

装饰器Decorator@classmethod 会让方法接收当前类 cls。它很适合命名工厂:使用 cls(...) 而非写死 Agent(...),子类继承时更自然。

8.3 静态方法

@staticmethod
def is_valid_name(name: str) -> bool:
    return bool(name.strip())

静态方法不接收 selfcls。它只是逻辑上属于该类,但不需要访问实例状态或类状态。

不要为了模仿 Java 工具类而大量使用静态方法。普通模块函数也是 Python 中很自然的组织方式。

九、完整示例

示例文件:

03_面向对象/3_1_Python与Java的类和对象/class_object_comparison.py

示例会直接输出五项差异:

  1. __init__ 与 Java 构造器的区别;
  2. selfthis 的区别;
  3. Python 属性的动态创建;
  4. 类属性与 static 字段的对应关系;
  5. Python 创建对象不写 new

十、运行方法

在项目根目录 D:\Code\Python 打开 PowerShell运行

python .\03_面向对象\3_1_Python与Java的类和对象\class_object_comparison.py

完成练习后运行:

python .\03_面向对象\3_1_Python与Java的类和对象\practice.py

十一、示例预期结果

输出中应依次看到“差异 1”到“差异 5”并看到

代码助手 使用 gpt-5.2运行平台Codex
动态添加的 status工作中
通过类读取Codex通过实例读取Codex
审查助手 使用 gpt-5运行平台Codex
名称是否合法True

十二、Java 开发者常见误区

12.1 创建对象时写 new

Python 没有这种语法,直接写:

agent = Agent("代码助手")

12.2 调用方法时手动传 self

调用 agent.describe() 时 Python 会自动绑定实例,不要写 agent.describe(agent)

12.3 忘记在方法定义中写 self

实例方法定义必须显式接收当前对象:

def describe(self) -> str:
    ...

self 不是保留关键字,但它是整个 Python 社区遵守的标准命名,不要改成其他名字。

12.4 把所有工厂方法都写成静态方法

如果方法需要创建“当前类”的实例,优先考虑 @classmethodcls(...),这比写死类名更适合继承。

12.5 认为没有 private 就无法封装

Python 更依赖约定、属性和接口设计。单下划线、双下划线及 property 会在下一课结合 Java 访问控制集中讲解。

12.6 用多个同名方法实现重载

Python 类体中后定义的同名方法会覆盖前一个定义,不能照搬 Java 重载。常见替代方式包括默认参数、关键字参数和单分派,后续按需讲解。

十三、课堂练习

打开 practice.py,完成一个 Book 类。练习覆盖:

  1. __init__ 和实例属性;
  2. self 和实例方法;
  3. 类属性;
  4. @classmethod 命名工厂;
  5. @staticmethod 校验方法;
  6. 不使用 new 创建并运行对象。

每部分都附有 Java 对照提醒和最终预期输出,因此可以直接从练习开始。

十四、参考答案

参考答案暂不写入 practice.py,避免直接照抄。完成后可以把代码交给我,我会从以下三方面反馈:

  1. 正确性:对象创建、属性和方法结果是否正确;
  2. 可读性:命名、结构和注释是否符合 Python 习惯;
  3. 知识掌握:是否仍残留 Java 式写法,能否解释选择原因。

十五、本课小结

  • Python 用 class 定义类,但通常不写 public
  • 使用 __init__ 初始化实例,创建对象时不写 new
  • self 类似 Java this,在定义实例方法时必须显式声明;
  • 实例属性通常通过 self.xxx__init__ 中建立;
  • 类属性类似 static 字段,但实例同名赋值会产生遮蔽;
  • @classmethod 接收 cls,适合可继承的命名工厂;
  • @staticmethod 不接收实例或类,只处理与类有关的独立逻辑;
  • Python 更动态,但成熟项目仍需要稳定、清晰的对象结构。

十六、验收标准

  • 能不使用 new 创建 Python 对象;
  • 能正确编写 __init__self
  • 能解释 self 与 Java this 的语法差异;
  • 能区分实例属性和类属性;
  • 能区分实例方法、类方法和静态方法;
  • 能解释为什么命名工厂中优先使用 cls(...)
  • 能指出 Python 不支持 Java 式同名方法重载;
  • practice.py 的实际输出与题目预期一致。