DAY 28 类的定义和方法

知识点回顾:

  1. 类的定义
  2. pass占位语句
  3. 类的初始化方法
  4. 类的普通方法
  5. 类的继承:属性的继承、方法的继承

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

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

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

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

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

一、Pass占位符和缩进

(1)有 pass

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

(2)无 pass

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

输出:报错

Cell In[2], line 3
    # pass  # pass 是一个占位符,表示这里暂时没有任何内容
                                      ^
IndentationError: expected an indented block

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

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

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

(1)条件语句

# 条件语句
x = 10
if x > 5:
  pass  # 如果这里是空的,就会报错
  # x = 1
else:
  print("x is not greater than 5")

(2)循环语句

# 循环语句
for i in range(3):
  pass  # 循环体是空的

(3)异常处理

try:
  # 尝试执行的代码
  print("aa")
except SomeError:
  pass  # 捕获到异常后执行的代码,这里需要内容
finally:
  pass  # 无论是否有异常,都会执行的代码,需要内容

总结:

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

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

二、类中的方法

1. 初始化方法

2. 普通方法

1、类的初始化方法

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

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

teacher = Teacher()  # 创建一个Teacher类的实例
print(teacher.name)

输出:

Susan

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

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

输出:

Dodo
23
Chinese

        其中,self.xx 是用来表明这个属性“归属于”这个类自己的(self)。比如 self.name,就代表着:“自己的名字”,self 等于“自己”,这个 self 指向类的实例化地址,传入的 self.xx 是它的属性。

        以后要是用它的属性值,即使是从外界参数传入的,前面也必须加上 self.xx,否则传入的参数没价值(例外的情况我们不提)。

        在Python类中, self 是一个指向实例对象本身的引用,并非类定义过程中的对象,而是在实例化时创建的。

2、类的普通方法

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

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

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

特性init 方法普通方法
调用时机创建实例时自动调用手动通过实例调用
是否需要显式调用
默认名称必须是 init自定义
主要用途初始化实例属性实现类的行为逻辑
参数要求第一个参数必须是 self第一个参数必须是 self
返回值必须返回 None(隐式)可以返回任意类型的值

class Teacher:
  def __init__(self):  # 初始化方法
    self.name = "Susan"
    self.age = 32
    self.subject = "Chinese"
  
  def introduce(self):  # 普通方法
    print(f"Hi, my name is {self.name}, and I am a {self.subject} teacher.")
  
  def teach_lesson(self):  # 普通方法
    print("上课中")

t = Teacher()
print(t.name)

t.introduce()  # 调用类的方法
t.teach_lesson()  # 调用类的方法

输出:

Susan
Hi, my name is Susan, and I am a Chinese 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类的实例
t = Teacher("Susan", "Chinese", 32)

# 调用教师的方法
t.teach_lesson()
t.criticize("Tom")  # 普通方法的参数 可以等到调用该方法的时候再传

输出:

Susan正在教Chinese。
Susan正在批评Tom。

三、类的继承

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

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

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

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

  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("Kaka", "Chinese", 32, 10)

# 调用继承的方法
master.teach_lesson()
master.criticize("Tom")

# 调用子类特有的方法
master.give_lecture("传统文化")

输出:

Kaka(高级教师)正在用高级方法教授Chinese。
Kaka正在批评Tom。
Kaka正在举办关于传统文化的讲座。

super( )重写父类方法

# 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()重写,保留父类方法的核心逻辑,并在其基础上扩展。

@ 浙大疏锦行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值