Python面向对象
Python 面向对象的核心是"一切皆对象":类也是对象,方法也是对象,类的定义本身就是可执行的代码。与 Java 相比,Python 没有接口/抽象类关键字(用 ABC 实现),支持多继承(C3 线性化解决冲突),属性通过魔术方法(__xxx__)钩入语言内置行为。理解"类定义即执行""self 只是约定""多继承 MRO",就掌握了 Python OOP 的三大特点。
"类定义即执行"的含义
class 语句执行时按顺序执行类体内的代码:方法定义(def)会创建函数对象并绑定为类属性,赋值语句(如 species = "犬科")直接设置类属性,print 等顶层语句也会立即执行——所以类体内除了方法定义,还能写初始化逻辑。这个机制是装饰器、@property、元类等进阶语法能工作的前提。
类与实例
类用 class 定义,实例通过 类名() 创建;__init__ 是初始化方法(不是构造器),__new__ 才是真正创建实例的类方法:
class Dog:
species = "犬科" # 类属性:所有实例共享
def __init__(self, name, age): # 初始化:设置实例属性
self.name = name # 实例属性
self.age = age
def bark(self): # 实例方法:第一个参数 self(约定,非关键字)
return f"{self.name}: 汪汪"
d = Dog("旺财", 2) # 创建实例
d.bark() # '旺财: 汪汪'
Dog.species # '犬科'(类属性)self 的真相
self 只是"实例自身"的约定名,调用 d.bark() 等价于 Dog.bark(d)——Python 把实例自动作为第一个参数传入。实例方法通过 self. 访问实例属性,类方法 @classmethod 收 cls、静态方法 @staticmethod 不收任何对象。
继承与多态
Python 支持多继承,用 C3 线性化算法(MRO)确定方法查找顺序;子类覆写父类方法即多态,super() 按 MRO 调用下一个:
class Animal:
def speak(self):
return "..."
class Dog(Animal):
def speak(self): # 覆写父类方法
return "汪汪"
class Cat(Animal):
def speak(self):
return "喵"
def make_speak(a: Animal): # 多态:接收任意 Animal 子类
return a.speak()
make_speak(Dog()) # '汪汪'
make_speak(Cat()) # '喵'多继承与 MRO
class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass # 菱形继承
D.__mro__ # (D, B, C, A, object) —— C3 保证基类只出现一次、子类在前MRO 与 super
super() 不是"调父类",而是"按 MRO 调下一个"——菱形继承中 super() 会正确走 B→C→A 的协作链,而 A.__init__() 直接调用会破坏协作。多继承冲突时用 __mro__ 查看顺序,尽量少用多继承(优先组合/混入 Mixin)。
魔术方法与运算符重载
魔术方法(Dunder Methods)让对象接入 Python 内置行为:len()、str()、+、下标访问、迭代、比较:
class Vector:
def __init__(self, x, y):
self.x, self.y = x, y
def __repr__(self): # 开发者表示(repr())
return f"Vector({self.x}, {self.y})"
def __str__(self): # 用户表示(str()/print)
return f"({self.x}, {self.y})"
def __add__(self, other): # 运算符重载: +
return Vector(self.x + other.x, self.y + other.y)
def __eq__(self, other): # == 值比较
return self.x == other.x and self.y == other.y
def __len__(self): # len() 支持
return 2
def __getitem__(self, i): # 下标访问 v[0]
return (self.x, self.y)[i]
def __iter__(self): # 迭代协议(见 Python语法 迭代器章节)
yield self.x
yield self.y
v1, v2 = Vector(1, 2), Vector(3, 4)
v1 + v2 # Vector(4, 6)
str(v1) # '(1, 2)'
v1 == Vector(1, 2) # True(默认是内存地址比较,覆写 __eq__ 后按值)
len(v1) # 2| 常用魔术方法 | 触发 |
|---|---|
__init__ / __new__ | 创建对象 |
__repr__ / __str__ | 字符串表示 |
__len__ / __getitem__ / __setitem__ | 容器协议 |
__iter__ / __next__ | 迭代协议 |
__eq__ / __lt__ / __hash__ | 比较与哈希 |
__enter__ / __exit__ | with 上下文管理器(见 Python异常处理) |
__call__ | 实例可调用(obj()) |
覆写 eq 必须同步 hash
对象进 set/dict 依赖 __hash__,覆写 __eq__ 后必须同步覆写 __hash__(相等对象哈希必相等),否则判重失效(与 Java 的 equals/hashCode 规则一致,见 Java面向对象)。
抽象基类与属性
from abc import ABC, abstractmethod
class Shape(ABC): # 抽象基类:不能实例化
@abstractmethod
def area(self): # 抽象方法:子类必须实现
pass
class Circle(Shape):
def __init__(self, r): self.r = r
def area(self): return 3.14 * self.r ** 2
# Shape() # TypeError: 抽象类不可实例化
Circle(2).area() # 12.56
class User:
def __init__(self, name):
self._name = name
@property # 属性:方法变属性访问
def name(self):
return self._name
@name.setter
def name(self, value): # 赋值时校验
if not value: raise ValueError("名字不能为空")
self._name = value@property 的用途
@property 把"计算属性/带校验的访问"封装成属性语法,调用方无需知道是字段还是方法——对外 API 稳定,内部实现可改(与 Java 的 getter/setter 定位一致)。@abstractmethod 对应 Java 的抽象方法/接口。
特殊方法:描述符与 slots
class Positive:
"""描述符:拦截属性访问,校验赋值"""
def __set_name__(self, owner, name):
self._name = f"_{name}"
def __get__(self, obj, objtype=None):
return getattr(obj, self._name, None)
def __set__(self, obj, value):
if value < 0: raise ValueError("必须为正数")
setattr(obj, self._name, value)
class Account:
balance = Positive() # 描述符实例作为类属性
a = Account()
a.balance = 100 # OK
a.balance = -5 # ValueErrorclass Slim:
__slots__ = ("x", "y") # 固定属性名:省内存(省 __dict__)
def __init__(self, x, y):
self.x, self.y = x, yslots 与描述符
__slots__ 声明固定属性集合,去掉每个实例的 __dict__,大量实例场景省内存(如百万级数据对象);描述符(实现 __get__/__set__ 的类)是 @property 的底层机制,也是 ORM(SQLAlchemy)字段校验的基础。两者都是"了解即可、按需使用"的进阶特性。
Python 面向对象与 Python语法 的类型系统、Python异常处理 的异常机制、Java面向对象 的 Java 对照(单继承+接口 vs 多继承+ABC)配合学习。