【Python学习打卡-Day28】类的蓝图:从模板到对象的构建艺术

📋 前言

各位伙伴们,大家好!Day 28 是我们编程思维的一次重大升级。在此之前,我们更多的是在编写指令的"脚本"。从今天起,我们将学习成为一名"设计师",开始构建拥有属性和行为的"对象"。我们将深入探索 Python 面向对象编程 (OOP) 的核心------类 (Class)

可以把 想象成一张 "饼干模具" ,它定义了饼干的形状和配方。而通过这个模具压出来的每一块具体的饼干,就是 对象 (Object)实例 (Instance)

今天,我们将从零开始,学习如何设计我们自己的"模具":

  • 如何定义一个类,以及 pass 的妙用。
  • 什么是 __init__ 方法?(给饼干注入灵魂)
  • 如何为类添加功能?(教会饼干"跳舞")
  • 什么是继承?(在"圆形模具"基础上,创造一个"花边圆形模具")

让我们一起进入对象的奇妙世界,体验创造的乐趣!


一、类的蓝图:定义与初始化 __init__

1.1 最简单的类与 pass

一个类最基本的结构是 class 关键字后跟类名。如果暂时不想写任何内容,可以使用 pass 作为占位符,避免程序因缺少代码块而报错。

python 复制代码
# 定义一个"狗"的类,但还没想好它有什么具体功能
class Dog:
    pass # pass 告诉 Python:"我知道这里需要代码,但先跳过。"

# 我们可以创建这个类的实例,尽管它什么也做不了
my_dog = Dog()
print(my_dog) # 输出: <__main__.Dog object at 0x...>

1.2 初始化方法 __init__:对象的诞生时刻

__init__ 是一个非常特殊的"魔法方法",也叫构造方法 。当一个对象被创建时(例如 my_dog = Dog()),__init__ 方法会自动被调用 。它的主要任务是设置这个新对象的初始状态,也就是它的属性 (Attributes)

  • self:是 __init__ 方法的第一个参数,它代表实例本身 。当你创建一个 my_dog 对象时,self 就指向 my_dog。通过 self.属性名 = 值 的方式,我们将属性"绑定"到这个实例上。
python 复制代码
class Dog:
    # 当一只狗"诞生"时,我们需要知道它的名字和年龄
    def __init__(self, name, age):
        print(f"一只名叫 {name} 的小狗诞生了!")
        # 使用 self 将传入的参数绑定为实例的属性
        self.name = name
        self.age = age

# 创建实例时,必须提供 __init__ 方法需要的参数(除了 self)
dog1 = Dog("旺财", 3)
dog2 = Dog("大黄", 5)

# 访问实例的属性
print(f"{dog1.name} 今年 {dog1.age} 岁了。") # 输出: 旺财 今年 3 岁了。
print(f"{dog2.name} 今年 {dog2.age} 岁了。") # 输出: 大黄 今年 5 岁了。

二、赋予蓝图生命:类的普通方法

如果说属性是对象"是什么"(名词),那么方法 (Methods) 就是对象"能做什么"(动词)。

普通方法是定义在类中、以 self 为第一个参数的函数。它必须通过实例来调用,并且可以访问和操作该实例的属性。

__init__ 方法 vs 普通方法 (来自课程的精炼总结)

特性 __init__ 方法 普通方法
调用时机 创建实例时自动调用 手动通过实例调用
是否需要显式调用
默认名称 必须是 __init__ 自定义
主要用途 初始化实例属性 实现类的行为逻辑
参数要求 第一个参数必须是 self 第一个参数必须是 self
返回值 必须返回 None(隐式) 可以返回任意类型的值
python 复制代码
class Dog:
    def __init__(self, name):
        self.name = name
    
    # 定义一个"叫"的方法
    def bark(self):
        print(f"{self.name} 正在汪汪叫!")
        
    # 定义一个带参数的"追逐"方法
    def chase(self, target):
        print(f"{self.name} 正在追逐 {target}!")

my_dog = Dog("旺财")

# 手动调用实例的方法
my_dog.bark()
my_dog.chase("一只猫")

三、站在巨人的肩膀上:类的继承

继承 是 OOP 的三大支柱之一。它允许我们创建一个新类(子类 ),这个新类可以继承一个已存在类(父类)的所有属性和方法。

这样做的好处是:

  • 代码复用:不用重写父类已有的功能。
  • 功能扩展:可以在子类中添加新功能。
  • 功能重写:可以修改父类的方法以适应子类的特殊需求。

super() 的妙用

在子类的 __init__ 方法中,我们通常需要调用 super().__init__(...)super() 函数会返回父类的实例,调用它的 __init__ 方法可以帮助我们完成父类部分的初始化工作,避免重复代码。

python 复制代码
# 定义父类:警犬
class PoliceDog(Dog): # 在括号中指定父类
    def __init__(self, name, department):
        # 1. 调用父类的 __init__ 来设置 name 属性
        super().__init__(name) 
        # 2. 添加子类特有的属性
        self.department = department

    # 3. 添加子类特有的方法
    def track_trace(self):
        print(f"来自 {self.department} 的警犬 {self.name} 正在追踪线索。")

    # 4. 重写父类的方法
    def bark(self):
        # 可以在重写时,通过 super() 调用父类的原始方法
        super().bark()
        print(f"{self.name} 的叫声充满了威严!")

# 创建子类实例
k9_dog = PoliceDog("雷神", "缉毒组")

# 调用继承自父类的方法
k9_dog.chase("嫌疑人") 

# 调用子类新增的方法
k9_dog.track_trace()

# 调用被子类重写的方法
k9_dog.bark()

四、作业实战:构建你的几何图形库

现在,让我们用今天学到的知识,来创建我们自己的几何图形类库吧!

题目一:定义圆 (Circle) 类

python 复制代码
import math

class Circle:
    """定义一个圆类"""
    def __init__(self, radius=1):
        """初始化方法,接收半径,默认为1"""
        self.radius = radius

    def calculate_area(self):
        """计算并返回圆的面积"""
        return math.pi * self.radius ** 2

    def calculate_circumference(self):
        """计算并返回圆的周长"""
        return 2 * math.pi * self.radius

# --- 示例运行 ---
circle = Circle(5)
print(f"半径: {circle.radius}")                          # 输出: 半径: 5
print(f"面积: {circle.calculate_area():.2f}")             # 输出: 面积: 78.54
print(f"周长: {circle.calculate_circumference():.2f}")     # 输出: 周长: 31.42

题目二:定义长方形 (Rectangle) 类

python 复制代码
class Rectangle:
    """定义一个长方形类"""
    def __init__(self, length=1, width=1):
        """初始化方法,接收长和宽,默认为1"""
        self.length = length
        self.width = width

    def calculate_area(self):
        """计算并返回面积"""
        return self.length * self.width

    def calculate_perimeter(self):
        """计算并返回周长"""
        return 2 * (self.length + self.width)

    def is_square(self):
        """判断是否为正方形,返回布尔值"""
        return self.length == self.width

# --- 示例运行 (长方形) ---
rect = Rectangle(4, 6)
print(f"长: {rect.length}, 宽: {rect.width}")     # 输出: 长: 4, 宽: 6
print(f"面积: {rect.calculate_area()}")           # 输出: 面积: 24
print(f"周长: {rect.calculate_perimeter()}")      # 输出: 周长: 20
print(f"是否为正方形: {rect.is_square()}")      # 输出: 是否为正方形: False

# --- 示例运行 (正方形) ---
square = Rectangle(5, 5)
print(f"\n是否为正方形: {square.is_square()}")      # 输出: 是否为正方形: True

题目三:图形工厂 (Shape Factory) 函数

这个题目是点睛之笔!它展示了如何动态地使用我们创建的类。

python 复制代码
def create_shape(shape_type, *args):
    """
    一个工厂函数,根据给定的类型和参数创建图形对象。
    :param shape_type: 字符串, "circle" 或 "rectangle"
    :param args: 创建对象所需的参数 (半径, 或 长和宽)
    :return: 对应的图形对象, 或 None (如果类型不支持)
    """
    if shape_type.lower() == "circle":
        # 如果是圆形,用 args 创建 Circle 实例
        # *args 会将元组解包,例如 (5,) -> 5
        return Circle(*args)
    elif shape_type.lower() == "rectangle":
        # 如果是矩形,用 args 创建 Rectangle 实例
        # *args 会将元组解包,例如 (3, 4) -> 3, 4
        return Rectangle(*args)
    else:
        # 如果类型未知,打印错误信息并返回 None
        print(f"错误: 不支持的图形类型 '{shape_type}'")
        return None

# --- 示例运行 ---
# 创建一个圆形
shape1 = create_shape("circle", 5)
if shape1:
    print(f"创建的圆形周长是: {shape1.calculate_circumference():.2f}") # 输出: 31.42

# 创建一个矩形
shape2 = create_shape("rectangle", 3, 4)
if shape2:
    print(f"创建的矩形是否为正方形: {shape2.is_square()}") # 输出: False

# 尝试创建一个不支持的图形
shape3 = create_shape("triangle", 10)

输出:

复制代码
创建的圆形周长是: 31.42
创建的矩形是否为正方形: False
错误: 不支持的图形类型 'triangle'

五、总结与心得

Day 28 的学习是编程思维的一次质变,我最大的感受有三点:

  1. 封装的力量 (Encapsulation) :我不再需要到处写计算圆面积的公式。我把半径 (self.radius) 和计算面积的方法 (calculate_area) 封装Circle 类里。使用者只需要知道如何创建一个 Circle 对象并调用它的方法,而无需关心内部实现细节。这让代码更安全、更易用。

  2. 抽象与蓝图 (Abstraction)class Circle 本身不是任何一个具体的圆,它是对所有"圆"这一概念的抽象。它定义了作为一个圆必须有什么(半径),能做什么(计算面积和周长)。这种"先设计蓝图,再创造实例"的思想,是解决复杂问题的基础。

  3. 组合与创造 (Composition & Factory) :"图形工厂"这个作业太妙了!它让我明白,类本身就是一种强大的"零件"。我们可以像搭积木一样,用一个更高层次的逻辑(工厂函数)来动态地组合和创造这些零件,构建出更灵活、更强大的系统。

从今天起,我看待代码的眼光不再仅仅是"一步步的指令",而是"一个个相互协作的对象"。这为理解未来复杂的机器学习库(它们都是用类构建的)打下了坚实的基础。

再次感谢 @浙大疏锦行 老师的精彩课程和巧妙的作业设计!

相关推荐
Lueeee.2 小时前
FFMPEG核心结构体
linux·ffmpeg
初九之潜龙勿用2 小时前
GMM NZ 全流程详解实战:FSDP MOE 训练加速
人工智能·pytorch·python
三品吉他手会点灯2 小时前
STM32F103 学习笔记-20-通信的基本概念
笔记·stm32·单片机·嵌入式硬件·学习
悠哉悠哉愿意2 小时前
【嵌入式学习笔记】GPIO与LED
笔记·单片机·嵌入式硬件·学习
怀旧,2 小时前
【Linux系统编程】14. 库使用与原理(上)
linux·运维·服务器
Mqh1807622 小时前
day47 预训练模型
python
QT 小鲜肉2 小时前
【Linux命令大全】001.文件管理之locate命令(实操篇)
linux·运维·服务器·chrome·笔记
嘻哈baby2 小时前
eBPF技术入门与实战:Linux内核黑科技
linux
崇山峻岭之间2 小时前
Matlab学习记录11
开发语言·学习·matlab