面向对象基础
设计模式基于面向对象编程(OOP),掌握OOP基础是学习设计模式的前提。本章将回顾面向对象的核心概念,为后续学习做准备。
类与对象
类的定义
类(Class)是对象的蓝图,定义了对象的属性和方法。
class Person:
"""人类"""
# 类属性
species = "人类"
def __init__(self, name, age):
"""构造方法"""
self.name = name # 实例属性
self.age = age
def introduce(self):
"""实例方法"""
return f"我叫{self.name},今年{self.age}岁"
@classmethod
def get_species(cls):
"""类方法"""
return cls.species
@staticmethod
def is_adult(age):
"""静态方法"""
return age >= 18
对象的创建
# 创建对象(实例化)
person1 = Person("张三", 25)
person2 = Person("李四", 30)
# 访问属性
print(person1.name) # 张三
print(person2.age) # 30
# 调用方法
print(person1.introduce()) # 我叫张三,今年25岁
print(Person.get_species()) # 人类
print(Person.is_adult(20)) # True
四大特性
1. 封装(Encapsulation)
封装是将数据和方法包装在一起,并隐藏内部实现细节。
class BankAccount:
"""银行账户 - 演示封装"""
def __init__(self, initial_balance):
self.__balance = initial_balance # 私有属性
def deposit(self, amount):
"""存款"""
if amount > 0:
self.__balance += amount
return True
return False
def withdraw(self, amount):
"""取款"""
if 0 < amount <= self.__balance:
self.__balance -= amount
return True
return False
def get_balance(self):
"""查询余额(只读访问)"""
return self.__balance
# 使用
account = BankAccount(1000)
account.deposit(500)
account.withdraw(200)
print(account.get_balance()) # 1300
# 无法直接修改余额
# account.__balance = 0 # 这样不行!
封装的好处: - ✅ 保护数据不被非法修改 - ✅ 隐藏实现细节 - ✅ 提供统一的访问接口
2. 继承(Inheritance)
继承是从已有类创建新类,实现代码复用。
class Animal:
"""动物基类"""
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError("子类必须实现speak方法")
def eat(self):
return f"{self.name}正在吃东西"
class Dog(Animal):
"""狗类 - 继承Animal"""
def speak(self):
return f"{self.name}:汪汪!"
class Cat(Animal):
"""猫类 - 继承Animal"""
def speak(self):
return f"{self.name}:喵喵!"
# 使用
dog = Dog("旺财")
cat = Cat("咪咪")
print(dog.speak()) # 旺财:汪汪!
print(cat.eat()) # 咪咪正在吃东西
继承的关系:
Animal
/ \
Dog Cat
3. 多态(Polymorphism)
多态是同一方法在不同对象上有不同行为。
class Shape:
"""形状基类"""
def draw(self):
raise NotImplementedError
class Circle(Shape):
def draw(self):
return "画一个圆形"
class Rectangle(Shape):
def draw(self):
return "画一个矩形"
class Triangle(Shape):
def draw(self):
return "画一个三角形"
def draw_shape(shape: Shape):
"""统一接口,处理不同形状"""
print(shape.draw())
# 多态调用
shapes = [Circle(), Rectangle(), Triangle()]
for shape in shapes:
draw_shape(shape)
# 输出:
# 画一个圆形
# 画一个矩形
# 画一个三角形
4. 抽象(Abstraction)
抽象是隐藏复杂细节,只暴露必要的接口。
from abc import ABC, abstractmethod
class Vehicle(ABC):
"""交通工具抽象类"""
@abstractmethod
def start(self):
"""启动"""
pass
@abstractmethod
def stop(self):
"""停止"""
pass
def get_info(self):
"""非抽象方法"""
return "这是一个交通工具"
class Car(Vehicle):
"""汽车"""
def start(self):
return "汽车启动"
def stop(self):
return "汽车停止"
class Bike(Vehicle):
"""自行车"""
def start(self):
return "骑行开始"
def stop(self):
return "骑行结束"
# 不能直接实例化抽象类
# vehicle = Vehicle() # 报错!
car = Car()
print(car.start()) # 汽车启动
print(car.get_info()) # 这是一个交通工具
方法类型
graph TB
A[方法类型] --> B[实例方法]
A --> C[类方法]
A --> D[静态方法]
B --> B1[self作为第一个参数]
B --> B2[访问实例和类属性]
B --> B3[最常用的方法]
C --> C1[cls作为第一个参数]
C --> C2[只能访问类属性]
C --> C3[@classmethod装饰器]
D --> D1[无特殊参数]
D --> D2[不访问任何属性]
D --> D3[@staticmethod装饰器]
style A fill:#ede7f6,stroke:#5e35b1,stroke-width:3px
style B fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
style C fill:#fff9c4,stroke:#f9a825,stroke-width:2px
style D fill:#c8e6c9,stroke:#43a047,stroke-width:2px
示例对比
class Calculator:
"""计算器类"""
PI = 3.14159
def __init__(self, value):
self.value = value
def add(self, x):
"""实例方法:使用self"""
return self.value + x
@classmethod
def circle_area(cls, radius):
"""类方法:使用cls"""
return cls.PI * radius ** 2
@staticmethod
def is_even(number):
"""静态方法:无self/cls"""
return number % 2 == 0
# 使用
calc = Calculator(10)
# 实例方法
print(calc.add(5)) # 15
# 类方法(通过类或实例调用)
print(Calculator.circle_area(5)) # 78.53975
print(calc.circle_area(5)) # 78.53975
# 静态方法
print(Calculator.is_even(4)) # True
print(calc.is_even(3)) # False
鸭子类型(Duck Typing)
Python 的鸭子类型:"如果它走起来像鸭子,叫起来像鸭子,那它就是鸭子。"
class Duck:
def speak(self):
return "嘎嘎嘎"
class Person:
def speak(self):
return "说话"
def make_sound(thing):
"""只要对象有speak方法就可以"""
print(thing.speak())
# 不需要继承或实现接口
make_sound(Duck()) # 嘎嘎嘎
make_sound(Person()) # 说话
鸭子类型让代码更灵活,但也需要开发者约定好接口规范。
属性访问控制
graph LR
A[属性] --> B[public]
A --> C[_protected]
A --> D[__private]
B --> B1[公开]
C --> C1[保护(约定)]
D --> D1[私有(名称改写)]
style A fill:#ede7f6,stroke:#5e35b1,stroke-width:3px
style B fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
style C fill:#fff9c4,stroke:#f9a825,stroke-width:2px
style D fill:#c8e6c9,stroke:#43a047,stroke-width:2px
class Example:
def __init__(self):
self.public = "公开属性"
self._protected = "保护属性" # 约定:内部使用
self.__private = "私有属性" # 名称改写:_Example__private
obj = Example()
print(obj.public) # ✅ 公开属性
print(obj._protected) # ⚠️ 可以访问,但不推荐
# print(obj.__private) # ❌ 报错:AttributeError
# Python的"私有"通过名称改写实现
print(obj._Example__private) # ✅ 私有属性(通过改写后的名称访问)
魔术方法
魔术方法(Magic Methods)是以双下划线开头和结尾的特殊方法,用于实现自定义行为。
class Vector:
"""向量类 - 演示魔术方法"""
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
"""str()输出"""
return f"Vector({self.x}, {self.y})"
def __repr__(self):
"""repr()输出(调试用)"""
return f"Vector(x={self.x}, y={self.y})"
def __add__(self, other):
"""+运算符"""
return Vector(self.x + other.x, self.y + other.y)
def __len__(self):
"""len()函数"""
return int((self.x ** 2 + self.y ** 2) ** 0.5)
def __getitem__(self, index):
"""索引访问"""
if index == 0:
return self.x
elif index == 1:
return self.y
else:
raise IndexError("索引超出范围")
# 使用
v1 = Vector(3, 4)
v2 = Vector(1, 2)
print(str(v1)) # Vector(3, 4)
print(repr(v1)) # Vector(x=3, y=4)
v3 = v1 + v2 # 调用 __add__
print(v3) # Vector(4, 6)
print(len(v1)) # 5
print(v1[0]) # 3
print(v1[1]) # 4
类的继承层次
graph TB
A[object] --> B[Base Class]
B --> C[Subclass A]
B --> D[Subclass B]
C --> E[Sub-subclass]
D --> F[Subclass B2]
style A fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
style B fill:#fff9c4,stroke:#f9a825,stroke-width:2px
style C fill:#c8e6c9,stroke:#43a047,stroke-width:2px
style D fill:#c8e6c9,stroke:#43a047,stroke-width:2px
style E fill:#a5d6a7,stroke:#2e7d32,stroke-width:2px
style F fill:#a5d6a7,stroke:#2e7d32,stroke-width:2px
super()函数
super() 用于调用父类方法。
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return "动物叫声"
class Dog(Animal):
def __init__(self, name, breed):
# 调用父类的__init__
super().__init__(name)
self.breed = breed
def speak(self):
# 调用父类方法并扩展
base_sound = super().speak()
return f"{base_sound}(汪汪)"
dog = Dog("旺财", "哈士奇")
print(dog.name) # 旺财
print(dog.breed) # 哈士奇
print(dog.speak()) # 动物叫声(汪汪)
多重继承
Python 支持多重继承,但需要谨慎使用。
class Flyable:
def fly(self):
return "会飞"
class Swimmable:
def swim(self):
return "会游泳"
class Duck(Flyable, Swimmable):
def speak(self):
return "嘎嘎嘎"
duck = Duck()
print(duck.fly()) # 会飞
print(duck.swim()) # 会游泳
print(duck.speak()) # 嘎嘎嘎
本章要点
- ✅ 类是对象的蓝图,对象是类的实例
- ✅ 封装、继承、多态、抽象是OOP四大特性
- ✅ Python有实例方法、类方法、静态方法三种方法
- ✅ 鸭子类型让Python的OOP更灵活
- ✅ 魔术方法实现自定义行为
- ✅
super()用于调用父类方法 - ✅ Python支持多重继承但需谨慎使用
下一步:SOLID原则 🚀