7.1 类和对象基础
7.1.1 类的定义
python
复制代码
# 基本语法
class ClassName:
"""类的文档字符串"""
# 类属性
class_variable = "类属性"
# 构造方法
def __init__(self, param):
# 实例属性
self.instance_variable = param
# 实例方法
def method(self):
pass
# 简单示例
class Dog:
"""狗类"""
def __init__(self, name, age):
"""构造方法"""
self.name = name
self.age = age
def bark(self):
"""叫的方法"""
print(f"{self.name}在汪汪叫!")
def get_info(self):
"""获取信息"""
return f"{self.name},{self.age}岁"
# 创建对象(实例化)
dog1 = Dog("旺财", 3)
dog2 = Dog("小黑", 2)
# 调用方法
dog1.bark() # 旺财在汪汪叫!
print(dog1.get_info()) # 旺财,3岁
# 访问属性
print(dog1.name) # 旺财
print(dog1.age) # 3
# 修改属性
dog1.age = 4
print(dog1.age) # 4
7.1.2 self参数
python
复制代码
class Person:
def __init__(self, name):
self.name = name # self代表实例本身
def greet(self):
# self用于访问实例属性
print(f"你好,我是{self.name}")
def change_name(self, new_name):
# self用于修改实例属性
self.name = new_name
person = Person("Alice")
person.greet() # 你好,我是Alice
person.change_name("Bob")
person.greet() # 你好,我是Bob
# self不是关键字,可以用其他名字(但强烈不推荐)
class Example:
def method(this): # 不推荐
print("可以工作,但不要这样做")
7.1.3 类属性与实例属性
python
复制代码
class Student:
# 类属性(所有实例共享)
school = "清华大学"
count = 0
def __init__(self, name, age):
# 实例属性(每个实例独有)
self.name = name
self.age = age
Student.count += 1 # 修改类属性
# 访问类属性
print(Student.school) # 清华大学
print(Student.count) # 0
# 创建实例
s1 = Student("Alice", 20)
s2 = Student("Bob", 21)
# 通过实例访问类属性
print(s1.school) # 清华大学
print(s2.school) # 清华大学
# 类属性被所有实例共享
print(Student.count) # 2
# 实例属性独立
print(s1.name) # Alice
print(s2.name) # Bob
# 注意:实例可以创建同名属性覆盖类属性
s1.school = "北京大学"
print(s1.school) # 北京大学(实例属性)
print(s2.school) # 清华大学(类属性)
print(Student.school) # 清华大学(类属性未变)
# 删除实例属性后,又可以访问类属性
del s1.school
print(s1.school) # 清华大学
7.1.4 类方法和静态方法
python
复制代码
class MyClass:
class_var = 0
def __init__(self, value):
self.instance_var = value
# 实例方法(第一个参数是self)
def instance_method(self):
print(f"实例方法,self={self}")
return self.instance_var
# 类方法(第一个参数是cls,用@classmethod装饰)
@classmethod
def class_method(cls):
print(f"类方法,cls={cls}")
return cls.class_var
# 静态方法(没有self或cls参数,用@staticmethod装饰)
@staticmethod
def static_method(x, y):
print("静态方法,不需要self或cls")
return x + y
# 调用实例方法
obj = MyClass(10)
obj.instance_method()
# 调用类方法(可以通过类或实例调用)
MyClass.class_method()
obj.class_method()
# 调用静态方法(可以通过类或实例调用)
MyClass.static_method(1, 2)
obj.static_method(1, 2)
# 实际应用示例
class Date:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
@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):
"""创建今天的日期"""
import datetime
today = datetime.date.today()
return cls(today.year, today.month, today.day)
@staticmethod
def is_valid_date(year, month, day):
"""验证日期是否有效"""
if month < 1 or month > 12:
return False
if day < 1 or day > 31:
return False
return True
def __str__(self):
return f"{self.year}-{self.month:02d}-{self.day:02d}"
# 使用
date1 = Date(2026, 1, 1)
date2 = Date.from_string("2026-12-31")
date3 = Date.today()
print(date1) # 2026-01-01
print(date2) # 2026-12-31
print(Date.is_valid_date(2026, 13, 1)) # False
7.2 封装
7.2.1 访问控制
python
复制代码
class BankAccount:
def __init__(self, owner, balance):
self.owner = owner # 公开属性
self._balance = balance # 受保护属性(约定,单下划线)
self.__password = "123456" # 私有属性(双下划线)
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
def __check_password(self, pwd):
"""私有方法"""
return pwd == self.__password
account = BankAccount("Alice", 1000)
# 公开属性可以直接访问
print(account.owner) # Alice
# 受保护属性可以访问,但不建议(只是约定)
print(account._balance) # 1000
# 私有属性不能直接访问
# print(account.__password) # AttributeError
# 但可以通过名称改写访问(不推荐)
print(account._BankAccount__password) # 123456
# 正确做法:通过公开方法访问
print(account.get_balance()) # 1000
account.deposit(500)
print(account.get_balance()) # 1500
7.2.2 属性装饰器(@property)
python
复制代码
class Circle:
def __init__(self, radius):
self._radius = radius
# getter方法
@property
def radius(self):
"""半径"""
return self._radius
# setter方法
@radius.setter
def radius(self, value):
if value > 0:
self._radius = value
else:
raise ValueError("半径必须大于0")
# 计算属性(只读)
@property
def area(self):
"""面积"""
return 3.14159 * self._radius ** 2
@property
def circumference(self):
"""周长"""
return 2 * 3.14159 * self._radius
# 使用
circle = Circle(5)
# 像访问属性一样使用
print(circle.radius) # 5
print(circle.area) # 78.53975
# 修改属性
circle.radius = 10
print(circle.area) # 314.159
# 验证
# circle.radius = -5 # ValueError: 半径必须大于0
# 只读属性不能修改
# circle.area = 100 # AttributeError
# 更复杂的示例
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 first_name(self):
return self._first_name
@first_name.setter
def first_name(self, value):
if value:
self._first_name = value
else:
raise ValueError("名字不能为空")
@property
def last_name(self):
return self._last_name
@last_name.setter
def last_name(self, value):
if value:
self._last_name = value
else:
raise ValueError("姓氏不能为空")
person = Person("Alice", "Wang")
print(person.full_name) # Alice Wang
person.first_name = "Bob"
print(person.full_name) # Bob Wang
7.3 继承
7.3.1 单继承
python
复制代码
# 父类(基类、超类)
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
print(f"{self.name}发出声音")
def move(self):
print(f"{self.name}在移动")
# 子类(派生类)
class Dog(Animal):
def __init__(self, name, breed):
# 调用父类构造方法
super().__init__(name)
self.breed = breed
# 重写父类方法
def speak(self):
print(f"{self.name}在汪汪叫!")
# 新增方法
def fetch(self):
print(f"{self.name}去捡球")
class Cat(Animal):
def speak(self):
print(f"{self.name}在喵喵叫!")
def climb_tree(self):
print(f"{self.name}爬树")
# 使用
dog = Dog("旺财", "哈士奇")
cat = Cat("小花")
dog.speak() # 旺财在汪汪叫!(重写的方法)
dog.move() # 旺财在移动(继承的方法)
dog.fetch() # 旺财去捡球(新增的方法)
cat.speak() # 小花在喵喵叫!
cat.climb_tree() # 小花爬树
# isinstance() - 检查是否是某个类的实例
print(isinstance(dog, Dog)) # True
print(isinstance(dog, Animal)) # True(子类实例也是父类实例)
print(isinstance(dog, Cat)) # False
# issubclass() - 检查是否是某个类的子类
print(issubclass(Dog, Animal)) # True
print(issubclass(Dog, Cat)) # False
7.3.2 多继承
python
复制代码
class Flyable:
def fly(self):
print("飞行中...")
class Swimmable:
def swim(self):
print("游泳中...")
# 多继承
class Duck(Animal, Flyable, Swimmable):
def speak(self):
print("嘎嘎嘎!")
duck = Duck("唐老鸭")
duck.speak() # 嘎嘎嘎!
duck.move() # 唐老鸭在移动
duck.fly() # 飞行中...
duck.swim() # 游泳中...
# 方法解析顺序(MRO - Method Resolution Order)
print(Duck.__mro__)
# 或
print(Duck.mro())
7.3.3 super()函数
python
复制代码
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
print(f"我是{self.name},{self.age}岁")
class Student(Person):
def __init__(self, name, age, student_id):
# 调用父类的__init__
super().__init__(name, age)
self.student_id = student_id
def introduce(self):
# 调用父类的方法
super().introduce()
print(f"学号:{self.student_id}")
student = Student("Alice", 20, "S001")
student.introduce()
# 我是Alice,20岁
# 学号:S001
# 多继承中的super()
class A:
def method(self):
print("A.method")
class B(A):
def method(self):
print("B.method")
super().method()
class C(A):
def method(self):
print("C.method")
super().method()
class D(B, C):
def method(self):
print("D.method")
super().method()
d = D()
d.method()
# 输出:
# D.method
# B.method
# C.method
# A.method
print(D.__mro__)
# (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
7.4 多态
python
复制代码
# 多态:不同的对象对同一方法有不同的实现
class Shape:
def area(self):
pass
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.14159 * self.radius ** 2
def perimeter(self):
return 2 * 3.14159 * self.radius
# 多态的应用
def print_shape_info(shape):
"""接受任何Shape对象"""
print(f"面积:{shape.area()}")
print(f"周长:{shape.perimeter()}")
rect = Rectangle(4, 5)
circle = Circle(3)
print_shape_info(rect)
# 面积:20
# 周长:18
print_shape_info(circle)
# 面积:28.27431
# 周长:18.84954
# 鸭子类型(Duck Typing)
# "如果它走起来像鸭子,叫起来像鸭子,那么它就是鸭子"
# Python不检查类型,只要有对应的方法就可以
class Triangle:
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def area(self):
s = (self.a + self.b + self.c) / 2
return (s * (s - self.a) * (s - self.b) * (s - self.c)) ** 0.5
def perimeter(self):
return self.a + self.b + self.c
# Triangle不继承Shape,但也可以使用print_shape_info
triangle = Triangle(3, 4, 5)
print_shape_info(triangle) # 正常工作
7.5 特殊方法(魔术方法)
7.5.1 字符串表示
python
复制代码
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# __str__ - 用于print()和str()
def __str__(self):
return f"Person(name={self.name}, age={self.age})"
# __repr__ - 用于交互式环境和repr()
def __repr__(self):
return f"Person('{self.name}', {self.age})"
person = Person("Alice", 25)
print(person) # Person(name=Alice, age=25)(调用__str__)
print(repr(person)) # Person('Alice', 25)(调用__repr__)
print([person]) # [Person('Alice', 25)](列表中显示__repr__)
7.5.2 运算符重载
python
复制代码
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
# __add__ - 加法运算符+
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
# __sub__ - 减法运算符-
def __sub__(self, other):
return Vector(self.x - other.x, self.y - other.y)
# __mul__ - 乘法运算符*
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
# __eq__ - 相等运算符==
def __eq__(self, other):
return self.x == other.x and self.y == other.y
# __lt__ - 小于运算符<
def __lt__(self, other):
return self.magnitude() < other.magnitude()
def magnitude(self):
return (self.x ** 2 + self.y ** 2) ** 0.5
def __str__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(1, 2)
v2 = Vector(3, 4)
# 使用重载的运算符
v3 = v1 + v2
print(v3) # Vector(4, 6)
v4 = v2 - v1
print(v4) # Vector(2, 2)
v5 = v1 * 3
print(v5) # Vector(3, 6)
print(v1 == v2) # False
print(v1 < v2) # True
# 常用运算符重载方法
# __add__ +
# __sub__ -
# __mul__ *
# __truediv__ /
# __floordiv__ //
# __mod__ %
# __pow__ **
# __eq__ ==
# __ne__ !=
# __lt__ <
# __le__ <=
# __gt__ >
# __ge__ >=
7.5.3 容器相关方法
python
复制代码
class MyList:
def __init__(self):
self.data = []
# __len__ - len()函数
def __len__(self):
return len(self.data)
# __getitem__ - 索引访问obj[key]
def __getitem__(self, index):
return self.data[index]
# __setitem__ - 索引赋值obj[key] = value
def __setitem__(self, index, value):
self.data[index] = value
# __delitem__ - 删除元素del obj[key]
def __delitem__(self, index):
del self.data[index]
# __contains__ - in运算符
def __contains__(self, item):
return item in self.data
# __iter__ - 迭代
def __iter__(self):
return iter(self.data)
def append(self, item):
self.data.append(item)
mylist = MyList()
mylist.append(1)
mylist.append(2)
mylist.append(3)
print(len(mylist)) # 3
print(mylist[0]) # 1
mylist[0] = 10
print(mylist[0]) # 10
print(2 in mylist) # True
for item in mylist:
print(item) # 10, 2, 3
7.5.4 其他常用特殊方法
python
复制代码
class Counter:
def __init__(self, start=0):
self.count = start
# __call__ - 使对象可调用
def __call__(self):
self.count += 1
return self.count
# __bool__ - bool()函数
def __bool__(self):
return self.count > 0
counter = Counter()
print(counter()) # 1(像函数一样调用)
print(counter()) # 2
print(counter()) # 3
if counter: # 调用__bool__
print("Counter is True")
# __enter__ 和 __exit__ - 上下文管理器
class FileManager:
def __init__(self, filename):
self.filename = filename
def __enter__(self):
self.file = open(self.filename, 'w')
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
self.file.close()
with FileManager('test.txt') as f:
f.write('Hello')
7.6 抽象基类
python
复制代码
from abc import ABC, abstractmethod
# 抽象基类
class Shape(ABC):
@abstractmethod
def area(self):
"""必须实现的抽象方法"""
pass
@abstractmethod
def perimeter(self):
"""必须实现的抽象方法"""
pass
def describe(self):
"""可选实现的普通方法"""
print("这是一个形状")
# 不能实例化抽象类
# shape = Shape() # TypeError
# 必须实现所有抽象方法
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)
rect = Rectangle(4, 5)
print(rect.area()) # 20
rect.describe() # 这是一个形状
7.7 设计模式
7.7.1 单例模式
python
复制代码
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
s1 = Singleton()
s2 = Singleton()
print(s1 is s2) # True(同一个实例)
# 装饰器实现
def singleton(cls):
instances = {}
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
@singleton
class Database:
def __init__(self):
print("初始化数据库连接")
db1 = Database() # 初始化数据库连接
db2 = Database() # 不再初始化
print(db1 is db2) # True
7.7.2 工厂模式
python
复制代码
class Dog:
def speak(self):
return "汪汪"
class Cat:
def speak(self):
return "喵喵"
class AnimalFactory:
@staticmethod
def create_animal(animal_type):
if animal_type == "dog":
return Dog()
elif animal_type == "cat":
return Cat()
else:
raise ValueError(f"未知动物类型:{animal_type}")
# 使用
factory = AnimalFactory()
dog = factory.create_animal("dog")
cat = factory.create_animal("cat")
print(dog.speak()) # 汪汪
print(cat.speak()) # 喵喵
7.7.3 观察者模式
python
复制代码
class Subject:
def __init__(self):
self._observers = []
def attach(self, observer):
self._observers.append(observer)
def detach(self, observer):
self._observers.remove(observer)
def notify(self, message):
for observer in self._observers:
observer.update(message)
class Observer:
def __init__(self, name):
self.name = name
def update(self, message):
print(f"{self.name}收到消息:{message}")
# 使用
subject = Subject()
observer1 = Observer("观察者1")
observer2 = Observer("观察者2")
subject.attach(observer1)
subject.attach(observer2)
subject.notify("Hello")
# 观察者1收到消息:Hello
# 观察者2收到消息:Hello
7.8 参考资料
官方文档
学习资源
设计模式