☰
python学习day08——封装装饰器、继承、多态
2026/9/27 4:44:53 网站建设 项目流程

1.封装装饰器的写法

""" 书写封装代码的时候 关于装饰器的细节 1.通常情况下 我们先写@property 然后再写@xxx.setter(不然的话xxx会找不到报错) 2.setter装饰器前边的名字是根据@property装饰器对应的函数名命名的 """ class Test: ​ @property def name(self): return "get_name" ​ @name.setter def name(self,name): self.__name = name print(name) pass ​ t1=Test() ​ print(t1.name) ​ t1.name="test" print(t1.name)

2.对象的创建过程

创建对象:obj = 类名()对象创建分为2 大阶段:分配空间 → 初始化,对应两个魔法方法:

  1. __new__:创建、分配内存,生成空对象

  2. __init__:给空对象初始化属性

顺序:先__new__→ 再__init__

分步详解

第一步:调用__new__(cls, *args, **kwargs)

  • 第一个参数cls:当前类

  • 作用:开辟一块内存空间,创建并返回一个空的实例对象

  • 返回值:必须返回创建出来的对象super().__new__(cls)

  • 如果__new__没有返回对象,那么__init__不会执行!

__new__是真正造对象的工厂方法。

第二步:调用__init__(self, *args, **kwargs)

  • self就是__new__返回过来的那个空对象

  • 作用:给对象添加实例属性,做初始化赋值

  • __init__没有返回值,只能 return None

""" 对象的创建过程 ​ 创建对象对比 java写法:类名 对象名 = new 类名() 会通过构造方法创建对象 python写法:对象名 = 类名() ​ Python创建对象的过程 1.访问__new__函数 创建对象 __new__也是魔法函数 每个类默认自带的(继承自object) 这个函数只负责创建对象,最终由祖宗类object来执行,因为在Python中,只有object有权限访问底层c语言的代码 在堆内存开辟空间 创建对象 此时创建没有任何属性的对象 返回回来 传递给__init__函数 ​ 2.__init__函数接收__new__函数传入的对象 对此对象添加属性 并且赋予用户传入的值 ​ 3.完成对象创建 得到一个有具体属性和属性值的对象 ​ """ ​ class Person: def __new__(cls, *args, **kwargs): print("__new__函数执行了") return super().__new__(cls) ​ def __init__(self, name, age): print("__init__函数执行了") self.name = name self.age = age ​ pass ​ p1=Person("赵四",20) ​

3. 继承概念引入

""" 编写两个类 狗狗类 属性:名字 亲密值 健康值 品种 方法:介绍狗狗信息 企鹅类 属性:名字 亲密值 健康值 性别 方法:介绍企鹅信息 ​ 当前模块中编写了两个类 这两类中有相同的属性 和 相似度非常高的方法 这些如果每次都单独写一遍 是非常啰嗦的 冗余的代码 所以 我们应该考虑 只书写一遍 然后重复利用 使用继承优化 """ class Dog: def __init__(self, name, love, health, strain): self.name = name self.love = love self.health = health self.strain = strain ​ def print_info(self): print(f"狗狗的名字是{self.name}") print(f"狗狗的亲密值是{self.love}") print(f"狗狗的健康值是{self.health}") print(f"狗狗的品种是{self.strain}") pass ​ class Penguin: def __init__(self, name, love, health, sex): self.name = name self.love = love self.health = health self.sex = sex ​ def print_info(self): print(f"企鹅的名字是的{self.name}") print(f"企鹅的亲密值是的{self.love}") print(f"企鹅的健康值是的{self.health}") print(f"企鹅的性别是的{self.sex}") ​

4.使用继承优化宠物系统

""" ​ 继承的核心思想:子类与父类是is-a的关系 即子类是父类 (属于描述 也属于约束) 表示子类必须属于父类描述的这一大范围 才可以使用继承 ​ ​ 使用继承优化宠物系统 宠物类 将各个重复类中 重复的 共同的信息 编写到父类中、 子类 :书写各个子类独有的信息 ​ 狗狗类 属性:名字 亲密值 健康值 品种 方法:介绍狗狗信息 企鹅类 属性:名字 亲密值 健康值 性别 方法:介绍企鹅信息 ​ ​ 创建子类对象 并不会创建父类对象(注意!!!) ​ """ ​ class Pet: def __int__(self, name, love, health): self.name = name # 这里的self 指向某个具体的子类对象 当前使用的哪个子类对象 就指向谁 self.love = love # 这里的self 指向某个具体的子类对象 当前使用的哪个子类对象 就指向谁 self.health = health # 这里的self 指向某个具体的子类对象 当前使用的哪个子类对象 就指向谁 ​ def print_info(self): print(f"宠物的名字是{self.name}") print(f"宠物的亲密值是{self.love}") print(f"宠物的健康值是{self.health}") pass ​ class Dog(Pet): def __init__(self,strain,name,love,health): super().__int__(name,love,health) self.strain = strain pass ​ class Penguin(Pet): def __init__(self, sex , name, love, health): self.sex = sex super().__int__(name,love,health) # Java 中的写法 super(name,health,love) pass ​ d1 = Dog("金毛", "大黄" , 100 , 100) d1.print_info() ​ print("---------------------------------------------------------") ​ ​ p1 = Penguin("雌性" , "大白" , 100 , 100) p1.print_info()
4.1 什么是继承

继承:让一个类(子类 / 派生类)去获取另一个类(父类 / 基类)的属性和方法,实现代码复用,不用重复写相同代码。

父类:被继承的类 子类:继承别人的类

语法:

class 父类名: # 父类代码 ​ class 子类名(父类名): # 子类代码

5. 方法重写

如果子类的方法名和父类一样,子类优先执行自己的方法,覆盖父类。

class Animal: def eat(self): print("动物吃东西") ​ class Dog(Animal): # 重写父类eat def eat(self): print("狗狗吃骨头") ​ dog = Dog() dog.eat() # 输出:狗狗吃骨头
""" 之前通过子类调用父类中的 print_info()方法 只能打印所有宠物共有的三个信息 所以我们可以在子类中再编写新的方法 打印独有的信息 并且将父类中的打印方法 复用 实现组合的效果 ​ 现在我们在子类中编写了新的方法 实现了组合效果 但是每个子类都有一个不同的名字 这样随着后续宠物类的增多 将会导致程序结构混乱 我们应该使用一个统一的名字 不管任何宠物打印信息 都使用一个 程序结构更加统一 方便调用 ​ """ ​ class Pet: def __init__(self, name, love, health): self.name = name # 这里的self 指向某个具体的子类对象 当前使用的哪个子类对象 就指向谁 self.love = love # 这里的self 指向某个具体的子类对象 当前使用的哪个子类对象 就指向谁 self.health = health # 这里的self 指向某个具体的子类对象 当前使用的哪个子类对象 就指向谁 ​ def print_info(self): print(f"宠物的名字是{self.name}") print(f"宠物的亲密值是{self.love}") print(f"宠物的健康值是{self.health}") pass ​ class Dog(Pet): def __init__(self,strain,name,love,health): super().__init__(name,love,health) self.strain = strain ​ def print_dog(self): super().print_info() print(f"狗狗的品种是{self.strain}") pass ​ class Penguin(Pet): def __init__(self, sex , name, love, health): self.sex = sex super().__init__(name,love,health) # Java 中的写法 super(name,health,love) ​ def print_penguin(self): print(f"企鹅的性别是:{self.sex}") super().print_info() pass ​ d1 = Dog("金毛", "大黄" , 100 , 100) d1.print_dog() d1.print_info() ​ print("---------------------------------------------------------") ​ ​ p1 = Penguin("雌性" , "大白" , 100 , 100) p1.print_penguin()
""" 方法重写 : 子类的方法声明与父类一致 Method Override 子类方法覆盖父类方法 ​ ​ 单继承下的MRO机制: 调用某个方法 先从本类(子类)中查找 找到则直接调用 找不到则去直接父类中查找 后续重复这个操作 直到找到为止 ​ """ ​ class Pet: def __init__(self, name, love, health): self.name = name # 这里的self 指向某个具体的子类对象 当前使用的哪个子类对象 就指向谁 self.love = love # 这里的self 指向某个具体的子类对象 当前使用的哪个子类对象 就指向谁 self.health = health # 这里的self 指向某个具体的子类对象 当前使用的哪个子类对象 就指向谁 ​ def print_info(self): print(f"宠物的名字是{self.name}") print(f"宠物的亲密值是{self.love}") print(f"宠物的健康值是{self.health}") pass ​ class Dog(Pet): def __init__(self,strain,name,love,health): super().__init__(name,love,health) self.strain = strain ​ def print_info(self): super().print_info() print(f"狗狗的品种是{self.strain}") pass ​ class Penguin(Pet): def __init__(self, sex , name, love, health): self.sex = sex super().__init__(name,love,health) # Java 中的写法 super(name,health,love) ​ def print_info(self): print(f"企鹅的性别是:{self.sex}") super().print_info() ​ ​ pass ​ d1 = Dog("金毛", "大黄" , 100 , 100) d1.print_info() ​ print("---------------------------------------------------------") ​ p1 = Penguin("雌性" , "大白" , 100 , 100) p1.print_info()

6. 单继承下的MRO(Method Resolution Order)机制

Method Resolution Order : 方法查找顺序

单继承下的MRO,一层一层往上找

​ ​ class A: # def test(self): # print("A 类中的test函数")' ​ # def __str__(self): # return "A 类中重写的__str__()函数" pass ​ class B(A): # def test(self): # print("B 类中的test函数") ​ # def __str__(self): # return "B 类中重写的__str__()函数" pass ​ class C(B): # def test(self): # print("C 类中的test函数") ​ # def __str__(self): # return "C 类中重写的__str__()函数" pass ​ c1 = C() print(C.__mro__) # (<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>) # c1.test() print(c1.__str__())

7.多继承下的MRO机制

多继承:一个子类继承多个父类

多继承下的MRO,Python 会从左往右找再往上,找到就停止

⚠️ 开发中尽量少用复杂多继承,容易出现代码混乱。

""" Python是支持多继承的 一个类直接继承多个父类 (Java是单根继承) 多个类之间使用逗号分割即可 在多继承场景下 方法的MRO机制 如果存在多个并列的父类 那么方法的查找顺序 则从左到右 找到则直接调用 否则继续向上查找 ​ 分析object类存在的意义: 面向对象 也可以理解为 所有类对象都面向object 属于此类的子类对象 所有的类默认继承此类 此类表示对象 所以在此类中规定了任何一个对象 应该具备的行为 比如 __del__ __new__ __init__ 等等 ​ """ ​ class Person: def __str__(self): return "Person类中的__str__()函数" pass ​ class YellowPerson(Person): def __str__(self): return "YellowPerson类中的__str__()函数" pass ​ class Chinese(Person): def __str__(self): return "Chinese类中的__str__()函数" pass ​ class Student(YellowPerson,Chinese): def __str__(self): return "Student类中的__str__()函数" pass ​ s1 = Student() print(Student.__mro__) print(s1)

8.super () 调用父类方法

重写之后,如果还想保留父类原来的逻辑,用super()

class Animal: def eat(self): print("动物吃东西") ​ class Dog(Animal): def eat(self): super().eat() # 调用父类的eat方法 print("狗狗吃骨头") ​ dog = Dog() dog.eat() #输出: #动物吃东西 #狗狗吃骨头

super () 最常用于__init__构造函数!

重点:继承时构造方法__init__

⚠️ 如果子类自己写了__init__,不会自动调用父类的init,必须手动用 super 调用。

class Animal: def __init__(self, name): self.name = name ​ class Dog(Animal): def __init__(self, name, age): # 调用父类构造,把name传给父类 super().__init__(name) self.age = age ​ dog = Dog("旺财", 3) print(dog.name) print(dog.age)

9.issubclass () 判断继承关系

print(issubclass(Dog, Animal)) #True Dog是Animal子类

10.多态

10.1 概念

多态:同一个接口(方法名),传入不同的对象,执行不一样的代码。 前提条件(Python 实现多态一般要满足):

  1. 要有继承关系

  2. 子类重写父类的方法

Python 是鸭子类型,就算没有继承也能实现多态

# 父类 class Animal: def speak(self): pass ​ # 子类1 class Dog(Animal): def speak(self): print("汪汪汪") ​ # 子类2 class Cat(Animal): def speak(self): print("喵喵喵") ​ # 定义一个统一的函数,接收动物对象 def make_sound(animal): animal.speak() # 同一个方法名speak ​ # 传入不同对象,产生不同效果 dog = Dog() cat = Cat() ​ make_sound(dog) make_sound(cat)

输出:

汪汪汪 喵喵喵

👉make_sound函数根本不用关心你是 Dog 还是 Cat,只要对象有speak()方法就行。这就是多态。

10.2多态的好处

1.代码灵活,易扩展:以后新增动物,不用改make_sound函数代码

class Duck(Animal): def speak(self): print("嘎嘎嘎") ​ duck = Duck() make_sound(duck)

直接新增子类,原有函数完全不用修改 →开闭原则(对扩展开放,对修改关闭)

  1. 降低耦合:调用方和具体的类解绑

10.3 Python 鸭子类型(Python 特色多态,不需要继承!)

“鸭子测试”:看起来像鸭子,走路像鸭子,叫起来像鸭子,那它就是鸭子。 Python 不强制要求继承同一个父类,只要对象拥有同名方法,就可以实现多态。

class Dog: def speak(self): print("汪汪汪") class Cat: def speak(self): print("喵喵喵") class Person: def speak(self): print("你好呀") def make_sound(animal): animal.speak() make_sound(Dog()) make_sound(Cat()) make_sound(Person())

三个类没有任何继承关系,但是都有speak(),就可以传入同一个函数。

Java/C++ 必须继承父类才能做多态;Python 不需要,这就是鸭子类型。

10.4 抽象父类(规范子类必须重写方法)

有时候你希望:子类必须重写父类的 speak 方法,不然报错。 这时就要用到abc模块,创建抽象基类。

from abc import ABC, abstractmethod class Animal(ABC): # 抽象方法:没有实现,强制子类必须重写 @abstractmethod def speak(self): pass class Dog(Animal): def speak(self): print("汪汪汪") # 如果子类没有重写speak,实例化的时候就报错! # class Cat(Animal): # pass # cat = Cat() # TypeError dog = Dog() dog.speak()

抽象类不能直接创建对象:Animal()会报错。

@abstractmethod表示抽象方法 即没有方法体的方法

抽象类作用:制定一套标准、接口,约束子类必须实现某些方法,让多态更规范。

11 多态案例

from abc import ABC, abstractmethod # 支付抽象父类 class Pay(ABC): @abstractmethod def pay_money(self,money): pass # 微信支付 class WeChatPay(Pay): def pay_money(self, money): print(f"微信支付:{money}元") # 支付宝支付 class AliPay(Pay): def pay_money(self, money): print(f"支付宝支付:{money}元") # 统一收银台函数(多态入口) def checkout(pay_obj, money): pay_obj.pay_money(money) checkout(WeChatPay(), 100) checkout(AliPay(), 200)

后面新增银联支付,只需要新建一个子类,不用修改checkout函数。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询