Python训练营打卡——DAY28(2025.5.17)

目录

类的定义和方法

一、Pass占位符和缩进

二、类的初始化方法

三、类的普通方法

四、类的继承

五、通俗解释

1. ​​类(Class)就像饼干模具​​

2. ​​实例化:用模具做饼干​​

3. ​​继承:升级成圣诞饼干模具​​

4. 为什么学这个?

六、作业

题目1:定义圆(Circle)类

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

题目3:图形工厂


类的定义和方法

是对属性和方法的封装,可以理解为模板,通过对模板实例化可以实现调用这个类的属性和方法。比如创建一个随机森林类,然后就可以调用他的训练和预测方法。

现在我们来学一下自己定义一个类,这会让我们对于类这个对象理解的更加深刻

ps:类的操作很多,我们这里只说一些在深度学习领域最常见和通用的

一个常见的类的定义包括了:

  1. 关键字class
  2. 类名
  3. 语法固定符号冒号(:)
  4. 一个初始化函数__init__(self)

注意:init左右各有两个下划线__,需要传入self这个特殊的参数。


一、Pass占位符和缩进

class ClassName: # 类名通常遵循大驼峰命名法 (UpperCamelCase),即每个单词的首字母都大写,class是定义类的关键词
    # 类的代码块 (可以包含属性定义、方法定义等)
    pass # pass 是一个占位符,表示这里暂时没有任何内容
  Cell In[4], line 3
    # pass # pass 是一个占位符,表示这里暂时没有任何内容
                                     ^
SyntaxError: unexpected EOF while parsing

许多时候,当规划好准备写一个函数、或者一个类,关键词定义后,会先用pass占位,避免运行错误,等到想好写什么再去补上

比如def、class这些定义的关键词后,必须有一个有占据缩进位置的代码块。

还有下面这些依赖缩进的语句,都可以用pass语句来占位

# 条件语句
x = 10
if x > 5:
    pass# 如果这里是空的,就会报错,可以注释试一下,即使x=1也会报错
else:
    print("x is not greater than 5")
# 循环语句
for i in range(3):
    pass # 循环体是空的
try:
    # 尝试执行的代码
    print("hh")
except SomeError:
    pass# 捕获到异常后,这里需要代码
finally:
    pass# 无论如何都会执行的代码块,也需要内容
hh

总结: Python 通过缩进来定义代码块的结构。当解释器遇到像 def, class, if, for 这样的语句,并且后面跟着冒号 : 时,它就期望接下来会有一个或多个缩进的语句来构成这个代码块。如果它没有找到任何缩进的语句(即代码块是空的),它就无法确定这个结构的范围,因此会抛出 IndentationError。

pass 语句的存在就是为了解决这个问题:它本身不执行任何操作,但它是一个有效的 Python 语句。所以,当你需要一个语法上存在的代码块,但又暂时不想在其中放入任何实际的逻辑时,pass 就是一个完美的占位符,它告诉解释器:“这里有一个代码块,但它什么也不做。”


二、类的初始化方法

初始化方法又叫构造方法、特殊方法

类有2种方法

  1. 初始化方法
  2. 普通放大
class Teacher: # 这里不需要括号
  def __init__(self): #初始化方法,这里没有传入参数
    self.name = "Susan" # 给类定义一些属性
    self.subject = "English"
    self.age = 33

Teacher = Teacher() # 创建一个Teacher类的实例
print(Teacher.name) # 输出: Susan
Susan
class Teacher:
    def __init__(self, name, age):# 初始化方法,传入了参数
        self.name = name # 外界的参数,需要通过self.xxx来复制给类自己的属性
        self.age = age
        self.subject = "English"  # 这个属性仍然是在创建时就设定好的

# 创建一个Teacher对象的例子,构造方法的参数必须
teacher = Teacher("Susan", 33) # 如果在初始化方法中设置了非默认的参数,那么外界就必须要传入才行
print(teacher.name)  # 输出: Susan
print(teacher.age)   # 输出: 33
print(teacher.subject)  # 输出: English

其中,self.xx是用来表明这个属性“归属于”这个类自己的(self)。比如self.name,就代表着:“自己的名字”,self等于“自己”,这个self指向类的实例化地址,传入的self.xx是它的属性。 以后要是用它的属性值,即使是从外界参数传入的,前面也必须加上self.xx,否则传入的参数没价值(例外的情况我们不提)


三、类的普通方法

除了init方法(初始化方法,又名构造方法),还包含一些普通方法(自己定义)

普通方法和init方法的差别在于,init方法是类的构造方法,当创建对象时,会自动调用init方法----只要你创建这个类对象了,这个init函数就会执行

普通方法是只有你调用类的这个方法的时候,函数才会执行

特性init 方法普通方法
调用时机创建实例时自动调用手动通过实例调用
是否需要显式调用
默认名称必须是 init自定义
主要用途初始化实例属性实现类的行为逻辑
参数要求第一个参数必须是 self第一个参数必须是 self
返回值必须返回 None(隐式)可以返回任意类型的值
class Teacher:
    def __init__(self):
        self.name = "Susan"
        self.subject = "English"
        self.age = 33
    def teach_lesson(self):
        print("上课中")
    def criticize(self):
        print("批评人") 
t = Teacher()
t.teach_lesson() # 调用类的方法
t.criticize()
print(t.name)
上课中
批评人
Susan
class Teacher:
    # 初始化方法接受参数以动态设置教师的属性
    def __init__(self, name, subject, age):
        self.name = name
        self.subject = subject
        self.age = age

    # 不是init的都叫做普通方法
    # 普通方法,模拟教师上课的行为
    def teach_lesson(self):
        print(f"{self.name}正在教{self.subject}。")

    # 另一个普通方法,模拟教师批评学生的行为
    def criticize(self, student_name):
        print(f"{self.name}正在批评{student_name}。")


# 创建Teacher类的实例
teacher = Teacher("Susan", "English", 33)

# 调用教师的方法
teacher.teach_lesson()
teacher.criticize("John")#普通方法的参可以等到调用该方法的时候再传
Susan正在教English。
Susan正在批评John。

四、类的继承

类已经是比较优秀的封装了,封装了函数、封装了属性

正如装饰器进一步封装了函数的可复用的功能,装饰器函数封装了函数

那么有没有东西可以进一步封装类呢?这就引出了类的继承

在面向对象编程中,继承允许一个类(子类)继承另一个类(父类)的属性和方法,从而实现代码复用和功能扩展。子类可以:

  1. 复用父类的代码(无需重新实现)。

  2. 重写父类的方法(修改或增强功能)。

  3. 添加新的方法和属性(扩展功能)。

仔细观察下方实例代码的注释,写的非常详细

# 先沿用之前定义的teacher类
class Teacher:
    def __init__(self, name, subject, age):
        self.name = name
        self.subject = subject
        self.age = age

    def teach_lesson(self):
        print(f"{self.name}正在教{self.subject}。")

    def criticize(self, student_name):
        print(f"{self.name}正在批评{student_name}。")

# 继承 Teacher 类,起名特级教师
class MasterTeacher(Teacher): # 1. 继承需要在括号中指定父类
    def __init__(self, name, subject, age, experience_years):# 2. 继承的时候需要调用父类的构造方法,所以需要传入父类的参数,同时也可以传入自己的参数
        # 调用父类的构造方法初始化基本属性
        super().__init__(name, subject, age) # 3. 调用父类的构造方法,这里的super()是一个内置函数,返回父类的实例
        # 4. 此时子类自动拥有了父类的属性和方法
        # 添加子类特有的属性

        self.experience_years = experience_years # 5. 子类特有的属性可以在这里定义

    # 重写父类方法,增强功能-----如果子类定义了与父类同名的方法,子类实例会优先调用子类的方法。
    def teach_lesson(self): # 6. 重写父类的方法
        print(f"{self.name}(特级教师)正在用高级方法教授{self.subject}。")

    # 新增子类特有的方法
    def give_lecture(self, topic): 
        print(f"{self.name}正在举办关于{topic}的讲座。")

# 创建子类实例
master = MasterTeacher("王教授", "数学", 45, 20)

# 调用继承的方法
master.teach_lesson()     # 调用重写的父类的方法
master.criticize("李同学")  # 调用父类的方法,如果不修改方法,则可以直接继承父类的方法

# 调用子类特有的方法
master.give_lecture("微积分")  # 调用子类新增的方法
王教授(特级教师)正在用高级方法教授数学。
王教授正在批评李同学。
王教授正在举办关于微积分的讲座。
# super()函数 除了在构造方法中使用,还可以在其他方法中使用

# 定义一个父类
class Animal:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def speak(self):
        print(f"{self.name} 发出声音")
    
class Dog(Animal):
    def speak(self):
        super().speak()  # 先调用父类的方法
        print("汪汪叫")    # 再添加子类的行为

dog = Dog("旺财", 3)
dog.speak() 
旺财 发出声音
汪汪叫

所以重写父类的方法,也包含2种

  1. 直接重写:本质是会优先用子类的同名方法,完全替代父类方法,父类逻辑不会执行。
  2. 使用super()重写,保留父类方法的核心逻辑,并在其基础上扩展。

五、通俗解释

1. ​​类(Class)就像饼干模具​

想象你有一个小熊形状的饼干模具(类)。这个模具决定了:

  • ​属性​​:每块饼干都有颜色、大小、厚度(类的属性)
  • ​功能​​:用模具压出形状(类的方法)

​代码示例​​:

class 饼干模具:
    def __init__(self, 颜色, 大小):
        self.颜色 = 颜色  # 属性:颜色
        self.大小 = 大小  # 属性:大小
    
    def 压形状(self):    # 方法:压出小熊
        print(f"压出一块{self.颜色}的小熊饼干!")

2. ​​实例化:用模具做饼干​

当你用这个模具(类)实际做出一块饼干时,这就是​​实例化​​。每块饼干都可以不同。

饼干1 = 饼干模具("巧克力色", "大号")  # 做一块巧克力色大饼干
饼干2 = 饼干模具("草莓色", "小号")    # 做一块草莓色小饼干

饼干1.压形状()  # 输出:压出一块巧克力色的小熊饼干!

3. ​​继承:升级成圣诞饼干模具​

如果想做一个​​圣诞特别版​​饼干模具(子类),它继承原版的所有特点,还能加新功能:

  • 继承原模具的颜色、大小(继承属性)
  • 新增「撒糖霜」功能(扩展方法)
  • 把压形状改成圣诞树(重写方法)
class 圣诞饼干模具(饼干模具):      # 继承原模具
    def __init__(self, 颜色, 大小, 糖霜颜色):
        super().__init__(颜色, 大小)  # 先用父类的属性
        self.糖霜颜色 = 糖霜颜色      # 新增属性
    
    def 压形状(self):  # 重写:压出圣诞树
        print(f"压出一棵{self.颜色}的圣诞树!")
    
    def 撒糖霜(self):  # 新增方法
        print(f"撒上{self.糖霜颜色}的糖霜✨")

# 使用圣诞模具
圣诞饼干 = 圣诞饼干模具("金色", "中号", "红色")
圣诞饼干.压形状()  # 输出:压出一棵金色的圣诞树!
圣诞饼干.撒糖霜()  # 输出:撒上红色的糖霜✨

4. 为什么学这个?

  • ​封装​​:像用模具一样批量「生产」相似对象(比如批量创建神经网络模型)
  • ​继承​​:避免重复造轮子,比如「卷积神经网络」继承「神经网络」的基础功能,再添加卷积层
  • ​代码管理​​:类把数据和操作打包,就像把饼干原料和模具放在一个盒子里,方便使用

下次当你看到代码里的 class,就想象成「我要设计一个模具来批量生产某个东西」🍪 这样理解就容易多啦!


六、作业

题目1:定义圆(Circle)类

要求:

  1. 包含属性:半径 radius。
  2. 包含方法:

    ①calculate_area():计算圆的面积(公式:πr²)。

    ②calculate_circumference():计算圆的周长(公式:2πr)。

  3. 初始化时需传入半径,默认值为 1。
# 示例运行
circle = Circle(5)
print(f"半径:{circle.radius}")       # 输出:半径:5
print(f"面积:{circle.calculate_area()}")   # 输出:面积:78.54(保留两位小数)
print(f"周长:{circle.calculate_circumference()}") # 输出:周长:31.42(保留两位小数)
import math

# 题目1:圆类
class Circle:
    def __init__(self, radius=1):
        self.radius = radius
    
    def calculate_area(self):
        return round(math.pi * self.radius ** 2, 2)
    
    def calculate_circumference(self):
        return round(2 * math.pi * self.radius, 2)
# 题目1测试
circle = Circle(5)
print(f"半径:{circle.radius}")       # 输出:半径:5
print(f"面积:{circle.calculate_area()}")   # 输出:78.54
print(f"周长:{circle.calculate_circumference()}") # 输出:31.42

半径:5
面积:78.54
周长:31.42


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

  1. 包含属性:长 length、宽 width。
  2. 包含方法:

    ①calculate_area():计算面积(公式:长×宽)。

    ②calculate_perimeter():计算周长(公式:2×(长+宽))。 is_square() 方法,判断是否为正方形(长 == 宽)。

  3. 初始化时需传入长和宽,默认值均为 1。
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"是否为正方形:{square.is_square()}")  # 输出:是否为正方形:True
# 题目2:长方形类
class Rectangle:
    def __init__(self, length=1, width=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
# 题目2测试
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"是否为正方形:{square.is_square()}")  # 输出:True

长:4, 宽:6
面积:24
周长:20
是否为正方形:False
是否为正方形:True


题目3:图形工厂

创建一个工厂函数 create_shape(shape_type, *args),根据类型创建不同图形对象:图形工厂(函数或类)

shape_type="circle":创建圆(参数:半径)。

shape_type="rectangle":创建长方形(参数:长、宽)。

shape1 = create_shape("circle", 5)
print(shape1.calculate_circumference())  # 输出:31.42

shape2 = create_shape("rectangle", 3, 4)
print(shape2.is_square())                # 输出:False

# 题目3:图形工厂
def create_shape(shape_type, *args):
    if shape_type == "circle":
        return Circle(*args)
    elif shape_type == "rectangle":
        return Rectangle(*args)
    else:
        raise ValueError("Invalid shape type")
# 题目3测试
shape1 = create_shape("circle", 5)
print(shape1.calculate_circumference())  # 输出:31.42

shape2 = create_shape("rectangle", 3, 4)
print(shape2.is_square())                # 输出:False

31.42
False


@浙大疏锦行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值