1. 概述
1.1 什么是面向对象编程(OOP)
面向对象编程是一种编程范式,它使用”对象”来设计软件。对象包含数据(属性)和代码(方法)。
核心概念对比表:
| 概念 | 说明 | 示例 |
|---|---|---|
| 类(Class) | 对象的蓝图或模板 | class Dog: |
| 对象(Object) | 类的实例 | my_dog = Dog() |
| 属性(Attribute) | 对象的数据 | my_dog.name = "Buddy" |
| 方法(Method) | 对象的函数 | my_dog.bark() |
1.2 面向对象的三大特性
- 封装(Encapsulation):隐藏内部实现细节
- 继承(Inheritance):基于现有类创建新类
- 多态(Polymorphism):同一接口,不同实现
2. 类和对象
2.1 定义类
class Dog:
"""一个简单的Dog类"""
# 类属性
species = "Canis familiaris"
# 初始化方法(构造器)
def __init__(self, name, age):
# 实例属性
self.name = name
self.age = age
# 实例方法
def bark(self):
return f"{self.name} says Woof!"
def description(self):
return f"{self.name} is {self.age} years old"
2.2 创建对象(实例化)
# 创建两个Dog对象
dog1 = Dog("Buddy", 3)
dog2 = Dog("Max", 5)
# 访问属性
print(dog1.name) # 输出: Buddy
print(dog2.age) # 输出: 5
# 调用方法
print(dog1.bark()) # 输出: Buddy says Woof!
print(dog2.description()) # 输出: Max is 5 years old
# 访问类属性
print(Dog.species) # 输出: Canis familiaris
print(dog1.species) # 输出: Canis familiaris
2.3 __init__ 方法详解
| 特性 | 说明 |
|---|---|
| 作用 | 初始化对象状态 |
| 调用时机 | 创建对象时自动调用 |
| 第一个参数 | 必须是 self,指向新创建的对象 |
| 返回值 | 必须返回 None(隐式返回 None) |
class Person:
def __init__(self, name, age):
self.name = name # 正确:使用self访问实例属性
self.age = age
# 错误示例
def wrong_init(self, name):
name = name # 错误:这只是局部变量,没有赋值给实例
3. 封装
3.1 访问控制
Python没有真正的私有属性,但有以下约定:
| 约定 | 语法 | 说明 | 访问方式 |
|---|---|---|---|
| 公开 | attribute | 随处可访问 | obj.attribute |
| 受保护 | _attribute | 约定为内部使用 | obj._attribute |
| 私有 | __attribute | 名称修饰,外部难访问 | _ClassName__attribute |
3.2 封装示例
class BankAccount:
def __init__(self, account_number, balance=0):
self.account_number = account_number # 公开属性
self._balance = balance # 受保护属性(约定)
self.__pin = 1234 # 私有属性(名称修饰)
# 公开方法:获取余额
def get_balance(self):
return self._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 __validate_pin(self, pin):
return self.__pin == pin
# 使用封装的类
account = BankAccount("123456789", 1000)
print(account.get_balance()) # 输出: 1000
account.deposit(500)
print(account.get_balance()) # 输出: 1500
# 尝试访问私有属性(不推荐)
print(account._BankAccount__pin) # 输出: 1234(但不应该这样访问)
3.3 封装的最佳实践
class Temperature:
def __init__(self, celsius=0):
self._celsius = celsius
# 使用属性装饰器提供更安全的访问方式
@property
def celsius(self):
return self._celsius
@celsius.setter
def celsius(self, value):
if value < -273.15: # 绝对零度
raise ValueError("温度不能低于绝对零度")
self._celsius = value
@property
def fahrenheit(self):
return self._celsius * 9/5 + 32
# 使用
temp = Temperature(25)
print(temp.celsius) # 输出: 25
print(temp.fahrenheit) # 输出: 77.0
temp.celsius = 30 # 使用setter
4. 继承
4.1 基本继承
# 父类(基类)
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError("子类必须实现此方法")
def sleep(self):
return f"{self.name} is sleeping"
# 子类(派生类)
class Dog(Animal):
def __init__(self, name, breed):
# 调用父类构造器
super().__init__(name)
self.breed = breed
# 重写父类方法
def speak(self):
return f"{self.name} says Woof!"
class Cat(Animal):
def __init__(self, name, color):
super().__init__(name)
self.color = color
def speak(self):
return f"{self.name} says Meow!"
# 使用继承
dog = Dog("Buddy", "Golden Retriever")
cat = Cat("Whiskers", "Tabby")
print(dog.speak()) # 输出: Buddy says Woof!
print(cat.speak()) # 输出: Whiskers says Meow!
print(dog.sleep()) # 输出: Buddy is sleeping(继承自父类)
4.2 super() 函数
super() 用于调用父类的方法:
class Parent:
def __init__(self, name):
self.name = name
def show(self):
return f"Parent: {self.name}"
class Child(Parent):
def __init__(self, name, age):
# 调用父类的__init__
super().__init__(name)
self.age = age
def show(self):
# 调用父类的show方法
parent_msg = super().show()
return f"{parent_msg}, Child: {self.age}"
child = Child("Alice", 10)
print(child.show()) # 输出: Parent: Alice, Child: 10
4.3 多继承
Python支持多继承,但需谨慎使用:
class Flyable:
def fly(self):
return "Flying..."
class Swimmable:
def swim(self):
return "Swimming..."
# 多继承
class Duck(Flyable, Swimmable):
def quack(self):
return "Quack!"
donald = Duck()
print(donald.fly()) # 输出: Flying...
print(donald.swim()) # 输出: Swimming...
print(donald.quack()) # 输出: Quack!
4.4 方法解析顺序(MRO)
Python使用C3算法确定方法解析顺序:
class A:
def show(self):
return "A"
class B(A):
def show(self):
return "B"
class C(A):
def show(self):
return "C"
class D(B, C):
pass
# 查看MRO
print(D.mro())
# 输出: [<class '__main__.D'>, <class '__main__.B'>,
# <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
d = D()
print(d.show()) # 输出: B(按照MRO顺序)
5. 多态
5.1 什么是多态
多态允许不同类的对象对同一消息做出不同的响应。
class Bird:
def fly(self):
return "Bird flying"
class Airplane:
def fly(self):
return "Airplane flying"
class Kite:
def fly(self):
return "Kite flying"
# 多态:同一方法名,不同实现
def let_it_fly(obj):
print(obj.fly())
# 不同对象调用同一方法
bird = Bird()
plane = Airplane()
kite = Kite()
let_it_fly(bird) # 输出: Bird flying
let_it_fly(plane) # 输出: Airplane flying
let_it_fly(kite) # 输出: Kite flying
5.2 鸭子类型(Duck Typing)
Python的多态基于鸭子类型:”如果它走起来像鸭子,叫起来像鸭子,那么它就是鸭子。”
class Dog:
def speak(self):
return "Woof!"
class Cat:
def speak(self):
return "Meow!"
class Duck:
def speak(self):
return "Quack!"
# 不需要共同的父类,只要有相同的方法即可
def make_animal_speak(animal):
print(animal.speak())
animals = [Dog(), Cat(), Duck()]
for animal in animals:
make_animal_speak(animal)
# 输出:
# Woof!
# Meow!
# Quack!
5.3 抽象基类(ABC)
使用abc模块定义抽象基类:
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimeter(self):
pass
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.14 * self.radius ** 2
def perimeter(self):
return 2 * 3.14 * self.radius
# 不能实例化抽象类
# shape = Shape() # 报错: TypeError
# 可以实例化具体子类
rect = Rectangle(5, 3)
circle = Circle(4)
print(rect.area()) # 输出: 15
print(circle.area()) # 输出: 50.24
6. 特殊方法
特殊方法(魔术方法)以双下划线开头和结尾,用于实现类的特定行为。
6.1 常用特殊方法表
| 方法 | 说明 | 触发方式 |
|---|---|---|
__init__ | 构造器 | obj = Class() |
__str__ | 字符串表示(友好) | str(obj), print(obj) |
__repr__ | 字符串表示(官方) | repr(obj) |
__len__ | 长度 | len(obj) |
__getitem__ | 索引访问 | obj[key] |
__setitem__ | 索引赋值 | obj[key] = value |
__delitem__ | 删除索引 | del obj[key] |
__iter__ | 迭代器 | for x in obj: |
__contains__ | 成员检测 | item in obj |
__eq__ | 相等比较 | obj1 == obj2 |
__lt__ | 小于比较 | obj1 < obj2 |
__add__ | 加法 | obj1 + obj2 |
__sub__ | 减法 | obj1 - obj2 |
__mul__ | 乘法 | obj1 * obj2 |
__enter__, __exit__ | 上下文管理器 | with obj: |
6.2 实现特殊方法示例
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"Vector({self.x}, {self.y})"
def __repr__(self):
return f"Vector({self.x}, {self.y})"
def __add__(self, other):
if isinstance(other, Vector):
return Vector(self.x + other.x, self.y + other.y)
return NotImplemented
def __sub__(self, other):
if isinstance(other, Vector):
return Vector(self.x - other.x, self.y - other.y)
return NotImplemented
def __eq__(self, other):
if isinstance(other, Vector):
return self.x == other.x and self.y == other.y
return False
def __len__(self):
# 向量的维度
return 2
def __abs__(self):
# 向量的模
return (self.x ** 2 + self.y ** 2) ** 0.5
# 使用特殊方法
v1 = Vector(3, 4)
v2 = Vector(1, 2)
print(v1) # 输出: Vector(3, 4)(调用__str__)
print(v1 + v2) # 输出: Vector(4, 6)(调用__add__)
print(v1 - v2) # 输出: Vector(2, 2)(调用__sub__)
print(v1 == v2) # 输出: False(调用__eq__)
print(len(v1)) # 输出: 2(调用__len__)
print(abs(v1)) # 输出: 5.0(调用__abs__)
6.3 容器类特殊方法
class ShoppingCart:
def __init__(self):
self.items = []
def add(self, item):
self.items.append(item)
def __len__(self):
return len(self.items)
def __getitem__(self, index):
return self.items[index]
def __setitem__(self, index, value):
self.items[index] = value
def __delitem__(self, index):
del self.items[index]
def __iter__(self):
return iter(self.items)
def __contains__(self, item):
return item in self.items
# 使用容器类
cart = ShoppingCart()
cart.add("Apple")
cart.add("Banana")
cart.add("Orange")
print(len(cart)) # 输出: 3
print(cart[0]) # 输出: Apple
print("Banana" in cart) # 输出: True
for item in cart:
print(item) # 输出: Apple, Banana, Orange
7. 属性装饰器
7.1 @property 装饰器
@property装饰器用于将方法转换为属性访问:
class Person:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
@property
def full_name(self):
"""只读属性"""
return f"{self.first_name} {self.last_name}"
@property
def email(self):
"""只读属性"""
return f"{self.first_name}.{self.last_name}@example.com"
@full_name.setter
def full_name(self, name):
"""可写属性"""
first, last = name.split()
self.first_name = first
self.last_name = last
# 使用@property
person = Person("John", "Doe")
print(person.full_name) # 输出: John Doe(像属性一样访问)
print(person.email) # 输出: John.Doe@example.com
person.full_name = "Jane Smith" # 使用setter
print(person.first_name) # 输出: Jane
print(person.last_name) # 输出: Smith
7.2 属性装饰器的最佳实践
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
"""半径的getter"""
return self._radius
@radius.setter
def radius(self, value):
"""半径的setter,包含验证"""
if value <= 0:
raise ValueError("半径必须为正数")
self._radius = value
@property
def area(self):
"""面积的只读属性"""
return 3.14 * self._radius ** 2
@property
def diameter(self):
"""直径的只读属性"""
return self._radius * 2
@diameter.setter
def diameter(self, value):
"""通过直径设置半径"""
self.radius = value / 2
# 使用
circle = Circle(5)
print(circle.radius) # 输出: 5
print(circle.area) # 输出: 78.5
print(circle.diameter) # 输出: 10
circle.diameter = 14
print(circle.radius) # 输出: 7.0
8. 类方法和静态方法
8.1 实例方法、类方法和静态方法对比
| 方法类型 | 装饰器 | 第一个参数 | 访问实例属性 | 访问类属性 | 调用方式 |
|---|---|---|---|---|---|
| 实例方法 | 无 | self | ✅ | ✅ | obj.method() |
| 类方法 | @classmethod | cls | ❌ | ✅ | Class.method() 或 obj.method() |
| 静态方法 | @staticmethod | 无 | ❌ | ❌ | Class.method() 或 obj.method() |
8.2 类方法(@classmethod)
类方法用于操作类本身,而不是实例:
class Date:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
def __str__(self):
return f"{self.year}-{self.month:02d}-{self.day:02d}"
# 类方法:作为备选构造器
@classmethod
def from_string(cls, date_string):
"""从字符串创建Date对象"""
year, month, day = map(int, date_string.split('-'))
return cls(year, month, day)
@classmethod
def today(cls):
"""创建表示今天的Date对象"""
import datetime
today = datetime.date.today()
return cls(today.year, today.month, today.day)
# 使用类方法
date1 = Date(2024, 5, 15)
date2 = Date.from_string("2024-12-25") # 使用类方法创建
date3 = Date.today() # 使用类方法创建
print(date1) # 输出: 2024-05-15
print(date2) # 输出: 2024-12-25
print(date3) # 输出: 2024-xx-xx(今天日期)
8.3 静态方法(@staticmethod)
静态方法与类相关,但不访问类或实例的状态:
import math
class MathUtils:
@staticmethod
def add(a, b):
return a + b
@staticmethod
def subtract(a, b):
return a - b
@staticmethod
def is_prime(n):
"""检查一个数是否为素数"""
if n <= 1:
return False
if n <= 3:
return True
if n % 2 == 0 or n % 3 == 0:
return False
i = 5
while i * i <= n:
if n % i == 0 or n % (i + 2) == 0:
return False
i += 6
return True
# 使用静态方法
print(MathUtils.add(5, 3)) # 输出: 8
print(MathUtils.subtract(10, 4)) # 输出: 6
print(MathUtils.is_prime(17)) # 输出: True
print(MathUtils.is_prime(15)) # 输出: False
8.4 实际应用示例
class Employee:
# 类属性
company = "Tech Corp"
employee_count = 0
def __init__(self, name, salary):
self.name = name
self.salary = salary
Employee.employee_count += 1
# 实例方法
def display(self):
return f"Employee: {self.name}, Salary: {self.salary}"
# 类方法:修改类属性
@classmethod
def set_company(cls, company_name):
cls.company = company_name
# 类方法:获取类属性
@classmethod
def get_employee_count(cls):
return cls.employee_count
# 静态方法:工具函数
@staticmethod
def is_valid_salary(salary):
return salary > 0
# 使用
emp1 = Employee("Alice", 50000)
emp2 = Employee("Bob", 60000)
print(Employee.get_employee_count()) # 输出: 2
print(Employee.company) # 输出: Tech Corp
Employee.set_company("New Tech Corp")
print(emp1.company) # 输出: New Tech Corp
print(Employee.is_valid_salary(50000)) # 输出: True
print(Employee.is_valid_salary(-1000)) # 输出: False
9. 实战示例
9.1 示例1:简单的学生管理系统
class Student:
def __init__(self, student_id, name, age):
self.student_id = student_id
self.name = name
self.age = age
self.courses = []
def enroll(self, course):
if course not in self.courses:
self.courses.append(course)
return True
return False
def get_info(self):
return {
"ID": self.student_id,
"Name": self.name,
"Age": self.age,
"Courses": self.courses
}
class Course:
def __init__(self, course_id, name, credits):
self.course_id = course_id
self.name = name
self.credits = credits
self.students = []
def add_student(self, student):
if student not in self.students:
self.students.append(student)
student.enroll(self.name)
return True
return False
def get_info(self):
return {
"ID": self.course_id,
"Name": self.name,
"Credits": self.credits,
"Students": [s.name for s in self.students]
}
# 使用学生管理系统
student1 = Student("S001", "Alice", 20)
student2 = Student("S002", "Bob", 21)
course1 = Course("C001", "Python Programming", 3)
course2 = Course("C002", "Data Structures", 4)
# 学生选课
course1.add_student(student1)
course1.add_student(student2)
course2.add_student(student1)
# 查看信息
print(student1.get_info())
# 输出: {'ID': 'S001', 'Name': 'Alice', 'Age': 20, 'Courses': ['Python Programming', 'Data Structures']}
print(course1.get_info())
# 输出: {'ID': 'C001', 'Name': 'Python Programming', 'Credits': 3, 'Students': ['Alice', 'Bob']}
9.2 示例2:简单的数据库连接池
import threading
import time
class DatabaseConnection:
"""模拟数据库连接"""
def __init__(self, connection_id):
self.connection_id = connection_id
self.in_use = False
def connect(self):
print(f"Connection {self.connection_id} connected")
def disconnect(self):
print(f"Connection {self.connection_id} disconnected")
def execute(self, query):
print(f"Connection {self.connection_id} executing: {query}")
return f"Result from connection {self.connection_id}"
class ConnectionPool:
"""数据库连接池"""
def __init__(self, max_connections):
self.max_connections = max_connections
self.connections = []
self.lock = threading.Lock()
# 初始化连接池
for i in range(max_connections):
conn = DatabaseConnection(i)
self.connections.append(conn)
def get_connection(self):
"""从连接池获取连接"""
with self.lock:
while True:
for conn in self.connections:
if not conn.in_use:
conn.in_use = True
conn.connect()
return conn
# 所有连接都在使用,等待
print("Waiting for available connection...")
time.sleep(0.1)
def release_connection(self, conn):
"""释放连接到连接池"""
with self.lock:
conn.in_use = False
conn.disconnect()
# 使用连接池
pool = ConnectionPool(max_connections=2)
def worker(worker_id):
"""工作线程函数"""
conn = pool.get_connection()
try:
result = conn.execute(f"SELECT * FROM table WHERE id = {worker_id}")
print(f"Worker {worker_id}: {result}")
finally:
pool.release_connection(conn)
# 创建多个线程使用连接池
threads = []
for i in range(5):
t = threading.Thread(target=worker, args=(i,))
threads.append(t)
t.start()
for t in threads:
t.join()
10. 最佳实践
10.1 命名规范
| 元素 | 约定 | 示例 |
|---|---|---|
| 类名 | PascalCase | MyClass |
| 方法名 | snake_case | get_name() |
| 属性名 | snake_case | self.first_name |
| 私有属性 | 前缀 __ | self.__private_attr |
| 受保护属性 | 前缀 _ | self._internal_attr |
| 常量 | UPPER_CASE | MAX_SIZE = 100 |
10.2 设计原则
- 单一职责原则(SRP):一个类应该只有一个引起变化的原因
- 开放封闭原则(OCP):对扩展开放,对修改封闭
- 里氏替换原则(LSP):子类必须能够替换父类
- 接口隔离原则(ISP):客户端不应该依赖它不需要的接口
- 依赖倒置原则(DIP):依赖抽象而不是具体实现
10.3 代码组织建议
# 良好的类组织结构示例
class ExampleClass:
"""类的文档字符串"""
# 1. 类属性
class_attribute = "value"
# 2. 初始化方法
def __init__(self, param1, param2):
self.param1 = param1
self.param2 = param2
# 3. 特殊方法
def __str__(self):
pass
def __repr__(self):
pass
# 4. 属性装饰器
@property
def property_name(self):
pass
# 5. 公共方法
def public_method(self):
pass
# 6. 私有方法
def _private_method(self):
pass
# 7. 类方法
@classmethod
def class_method(cls):
pass
# 8. 静态方法
@staticmethod
def static_method():
pass
10.4 常见陷阱和解决方案
| 陷阱 | 问题 | 解决方案 |
|---|---|---|
| 可变默认参数 | def func(x=[]) | 使用 x=None,在函数内检查 |
| 属性隐藏 | 子类属性覆盖父类属性 | 使用 super() 调用父类方法 |
| 循环导入 | 两个模块相互导入 | 重构代码或使用局部导入 |
| 深度继承 | 继承层次过深 | 使用组合代替继承 |
过度使用 @property | 简单属性也使用装饰器 | 只在需要验证或计算时使用 |
# 陷阱1:可变默认参数
class WrongExample:
def __init__(self, items=[]): # 错误!
self.items = items
class RightExample:
def __init__(self, items=None): # 正确
if items is None:
self.items = []
else:
self.items = items
# 陷阱2:属性隐藏
class Parent:
def show(self):
print("Parent")
class Child(Parent):
def show(self):
super().show() # 正确:调用父类方法
print("Child")
总结
Python面向对象编程提供了强大的工具来组织和管理代码。关键要点:
- 类与对象:类是蓝图,对象是实例
- 封装:使用命名约定和属性装饰器控制访问
- 继承:重用代码,建立is-a关系
- 多态:同一接口,不同实现
- 特殊方法:自定义类的行为
- 装饰器:@property、@classmethod、@staticmethod
- 最佳实践:遵循命名规范,应用设计原则
通过合理运用这些概念,可以编写出更清晰、更易维护的Python代码。
参考资料
- Python官方文档:https://docs.python.org/3/tutorial/classes.html
- PEP 8 — Python代码规范:https://peps.python.org/pep-0008/
- 《Fluent Python》 by Luciano Ramalho
- 《Python Cookbook》 by David Beazley and Brian K. Jones
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END













暂无评论内容