第07章-面向对象编程

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 参考资料

官方文档

学习资源

设计模式

相关推荐
小生不才yz8 小时前
行为型模式 - 模板方法模式
设计模式
zhaokuner8 小时前
06-聚合与一致性边界-DDD领域驱动设计
java·开发语言·设计模式·架构
技术小泽9 小时前
DDD领域设计精讲
java·后端·设计模式·架构
Geoking.9 小时前
简单工厂模式介绍
设计模式·简单工厂模式
zhaokuner10 小时前
08-仓储与映射-DDD领域驱动设计
java·开发语言·设计模式·架构
会员果汁11 小时前
7.设计模式-模板方法模式
算法·设计模式·模板方法模式
zhaokuner11 小时前
01-领域与问题空间-DDD领域驱动设计
java·开发语言·设计模式·架构
崎岖Qiu11 小时前
【设计模式笔记26】:深入浅出「观察者模式」
java·笔记·观察者模式·设计模式
zhaokuner12 小时前
02-通用语言与协作-DDD领域驱动设计
java·开发语言·设计模式·架构