python快速入门学习笔记十四:面向对象(下)继承、权限控制、多态、抽象类

  • 原创
  • 作者:程序员三丰
  • 发布时间:2026-03-25 11:44
  • 浏览量:17
python入门第十四课,主要是学习了面向对象编程的进阶知识,通过封装、继承和多态组织代码,将数据与行为结合,构建出模块化、可复用的程序结构。

继承

基本语法

概念:继承就是一个类可以继承另一个类的属性和方法。『父类』又称 『基类 或 超类』, 『子类』又称 『派生类』。

作用:通过继承可以实现代码的复用和扩展,避免重复编写相同的代码,让代码结构更简洁、更高效。

语法def 子类名(父类名),例如:def Student(Person)就表示定义了一个Student类继承自Person类。

在子类中,有两种方式去调用父类的初始化方法,来实现对继承属性的初始化操作:

❏ 方式1(推荐):super().__init__(param1, param2)

❏ 方式2:父类名.__init__(self, param1, param2)

子类独有的属性,需要自己手动完成初始化。

示例代码:

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

    def speak(self, msg):
        print(f'我叫{self.name},年龄{self.age},性别是{self.gender},我想说:{msg}')

# 定义一个Student类(子类),继承自Person类
class Student(Person):
    def __init__(self, name, age, gender, stu_id, grade):
        super().__init__(name, age, gender)

        self.stu_id = stu_id
        self.grade = grade

    def study(self):
        print(f'我叫{self.name},我在努力学习Python,争取做到{self.grade}年纪的第一名')

# 查看子类的属性和方法
print(Student.__dict__)

# 创建子类的实例对象
s1 = Student('李俊', 16, '男', '2026001', '初二')
print(s1.__dict__) # {'name': '李俊', 'age': 16, 'gender': '男', 'stu_id': '2026001', 'grade': '初二'}
print(type(s1)) # <class '__main__.Student'>

# 子类实例对象调用父类的方法
s1.speak('你好')

# 子类实例对象调用自己的方法
s1.study()

方法重写

如果子类中定义了与父类同名的方法,则子类方法会“覆盖”父类中同名的方法,又称:重写。

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

    def speak(self, msg):
        print(f'我叫{self.name},年龄{self.age},性别是{self.gender},我想说:{msg}')

# 定义一个Student类(子类),继承自Person类
class Student(Person):
    def __init__(self, name, age, gender, stu_id, grade):
        super().__init__(name, age, gender)

        self.stu_id = stu_id
        self.grade = grade

    def study(self):
        print(f'我叫{self.name},我在努力学习Python,争取做到{self.grade}年纪的第一名')

    # 方法重写
    def speak(self, msg):
        super().speak(msg)
        print(f'我是学生,我的学号是{self.stu_id},我正在读{self.grade}, 我想说:{msg}')

# 创建子类的实例对象
s1 = Student('李俊', 16, '男', '2026001', '初二')

# 子类实例对象调用自己的重写了父类方法
s1.speak('你好')

isinstance() 和 issubclass()

两个常用函数:

isinstance(obj, Class)判断对象是否为指定类或其子类的实例。

issubclass(Sub, Super)判断一个类是否是另一个类的子类。

示例代码:

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

    def speak(self, msg):
        print(f'我叫{self.name},年龄{self.age},性别是{self.gender},我想说:{msg}')

# 定义一个Student类(子类),继承自Person类
class Student(Person):
    def __init__(self, name, age, gender, stu_id, grade):
        super().__init__(name, age, gender)

        self.stu_id = stu_id
        self.grade = grade

    def study(self):
        print(f'我叫{self.name},我在努力学习Python,争取做到{self.grade}年纪的第一名')

    # 方法重写
    def speak(self, msg):
        # super().speak(msg)
        print(f'我是学生,我的学号是{self.stu_id},我正在读{self.grade}, 我想说:{msg}')

p1 = Person('张三', 18, '男')
s1 = Student('李俊', 16, '男', '2026001', '初二')

print(isinstance(s1, Student)) # True
print(isinstance(p1, Person)) # True
print(isinstance(s1, Person)) # True
print(isinstance(p1, Student))  # False

print(issubclass(Student, Person)) # True
print(issubclass(Person, Student))  # False
print(issubclass(Person, Person)) # True
print(issubclass(Student, Student)) # True

多重继承

概念:多重继承指一个类同时继承多个父类,从而拥有多个父类的属性和方法。

语法:

class 子类名(父类A, 父类B, ...):
    # 子类可以继承多个父类的属性和方法
    ...

下面的示例代码中,Student类同时继承Person类和Worker类。

# 定义一个Person类
class Person:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender
    def speak(self):
        print(f'我叫{self.name},年龄{self.age},性别{self.gender}')

# 定义一个Worker类
class Worder:
    def __init__(self, company):
        self.company = company
    def do_work(self):
        print(f'我在{self.company}做兼职')

# 定义一个Student类,继承自:Person类,Worker 类
class Student(Person, Worder):
    def __init__(self, name, age, gender, stu_id, grade, company):
        Person.__init__(self, name, age, gender)
        Worder.__init__(self, company)
        self.stu_id = stu_id
        self.grade = grade
    def study(self):
        print(f'我在很努力的学习,争取做{self.grade}年纪的第一名')

# 创建Student实例对象
s1 = Student('张三', 18, '男', '2026001', '大一', '肯德基')
print(s1.__dict__)
s1.speak()
s1.do_work()
s1.study()

# 查看属性和方法的查找顺序
print(Student.__mro__) # (<class '__main__.Student'>, <class '__main__.Person'>, <class '__main__.Worder'>, <class 'object'>)

扩展

类的__mro__ 属性用于记录属性和方法的查找顺序。

通过实例去查找属性和方法时,会先在实例自身上查找,如果没有,就按照__mro__中记录的顺序去查找。

权限控制

三种访问权限

在Python中,我们可以给属性赋予三种权限,分别是:

  • 公有属性:当前类内部、子类内部、类外部,都可以访问。
  • 受保护属性:当前类内部、子类内部,都可以访问。
  • 私有属性:仅能在当前类内部访问。

示例代码:

class Person:
    def __init__(self, name, age, idcard):
        self.name = name
        self._age = age
        self.__idcard = idcard
    def speak(self):
        # 类的内部,可以访问任何权限的属性(公有属性、受保护属性、私有属性)。
        print(f'我叫{self.name},年龄{self._age},身份证:{self.__idcard}')

class Student(Person):
    def hello(self):
        # 子类的内部可以访问:公有属性、受保护属性
        print(f'我是学生,我叫{self.name},年龄{self._age}')

p1 = Person('张三', 18, '110101199001011234')
# 类的外部,仅能访问公有属性
print(p1.name)
print(p1._age) # 在类的外部强制访问受保护的属性,也可以访问,但是不建议这样做
# print(p1.__idcard) # 运行时直接报错:AttributeError: 'Person' object has no attribute '__idcard'

# 扩展:Python 保护私有属性的方式是重命名,例如:__idcard属性,会被重命名为:_Person__idcard
print(p1.__dict__)
print(p1._Person__idcard) # 但是不建议这样访问

getter 和 setter

在面向对象编程中,我们会把一些内部数据保护起来,但同时还想提供一个“安全的通道”让外部访问。

这个时候我们就会用到:

  • getter:读取属性的方法。
  • setter:修改属性的方法。

在 Python 中,通过@property@xxx.setter语法,把普通方法变成属性一样使用的方法。

示例代码:

class Person:
    def __init__(self, name, age, idcard):
        self.name = name
        self._age = age
        self.__idcard = idcard

    # 注册 age 属性的 getter 方法,当访问 Person 实例的 age 属性时,会自动调用此方法
    @property
    def age(self):
        return self._age

    # 注册 age 属性的 setter 方法,当给 Person 实例的 age 属性赋值时,会自动调用此方法
    @age.setter
    def age(self, value):
        if (value <= 120):
            self._age = value
        else:
            print('年龄非法,已将年龄变为最大值120')
            self._age = 120

    # 注册 idcard 属性的 getter 方法,当访问 Person 实例的 idcard 属性时,会自动调用此方法
    @property
    def idcard(self):
        return self.__idcard[:6] + '********' + self.__idcard[-4:]

    # 注册 idcard 属性的 setter 方法,当给 Person 实例的 idcard 属性赋值时,内部会禁止修改身份证号并给出提示
    @idcard.setter
    def idcard(self, value):
        print('抱歉,身份证号不允许随意修改,如有特殊需求,请联系管理员')

p1 = Person('张三', 18, '110101199001011234')
print(p1.age)
print(p1.idcard)

p1.age = 21
print(p1.age)

p1.idcard = 'asdd'
print(p1.idcard)

print(p1.__dict__)
print(Person.__dict__)

魔术方法

概念:以__xxx__命名的特殊方法(双下划线开头和结尾)。

特点:不需要手动调用,在特定场景由 Python 自动调用。

几个常用的魔术方法:

示例代码:

class Person:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

    def __str__(self):
        return f'姓名:{self.name}, 年龄:{self.age}, 性别:{self.gender}'

    def __len__(self):
        return len(self.__dict__)

    def __lt__(self, other):
        return self.age < other.age

    def __gt__(self, other):
        return self.age > other.age

    def __eq__(self, other):
        return self.__dict__ == other.__dict__

    def __getattr__(self, name):
        print(f'您访问的{name}属性,不存在!')

p1 = Person('张三', 18, '男')
p2 = Person('李四', 21, '女')

print(p1)
print(str(p1))
print(len(p1))
print(p1 < p2)
print(p1 > p2)
print(p1 == p2)
print(p1.address)

object 类

object 是所有类的最终祖先,所有的类,无论写与不写,都继承自object。

object 提供了所有对象都会有的一组最基本的方法,例如:

上述这些方法,如果我们不去重写,Python 会自动继承并使用默认版本。

class Person:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender


# 验证所有的类都继承了 object 类
print(issubclass(Person, object))  # True
print(issubclass(int, object))  # True
print(issubclass(str, object))  # True
print(issubclass(bool, object))  # True
print(issubclass(list, object))  # True
print(issubclass(tuple, object))  # True
print(issubclass(set, object))  # True
print(issubclass(dict, object))  # True

print()

# 验证python中所有对象都是 object 类的实例
p1 = Person('张三', 18, '男')
print(isinstance(p1, object))  # True
print(isinstance(100, object))  # True
print(isinstance('hello', object))  # True
print(isinstance(False, object))  # True
print(isinstance([1, 2, 3], object))  # True
print(isinstance((1, 2, 3), object))  # True
print(isinstance({1, 2, 3}, object))  # True
print(isinstance({'James': 41, 'Kobe': 48}, object))  # True

# 查看 object 所有的属性和方法
for key in object.__dict__:
    print(key, object.__dict__[key])

print(p1.__dict__) # 打印对象自己身上的东西
print(dir(p1)) # 打印对象能访问到的东西

# 下面三种写法等价
print(p1.__str__())
print(p1)
print(str(p1))

多态

什么是多态

多态(Polymorphism)是面向对象编程的三大特性之一,指同一个操作或方法作用于不同类型的对象时,可以表现出不同的行为。简单来说,就是“一个接口,多种实现”。在 Python 中,多态主要通过以下两种形式:标准多态和鸭子多态,下面分别详细介绍。

  • 继承与方法重写:子类重写父类的方法,当使用父类类型的引用调用该方法时,实际执行的是子类的方法。这种形式又叫“传统多态”或“标准多态”。
  • 鸭子类型(Duck Typing):指一种编程风格,它并不依靠查找对象类型来确定其是否具有正确的接口,而是直接调用或使用其方法或属性(“看起来像鸭子,叫起来也像鸭子,那么肯定就是鸭子。”)

标准多态

标准多态,又叫“传统多态”,基于继承与方法重写:子类重写父类的方法,当使用父类类型的引用调用该方法时,实际执行的是子类的方法。

class Animal:
    def speak(self):
        print('动物正在发出声音')

class Dog(Animal):
    def speak(self):
        print('汪汪汪!')

class Cat(Animal):
    def speak(self):
        print('喵喵喵!')

# 注意:Pig类没有继承Animal类
class Pig:
    def speak(self):
        print('哼哼哼!')

# make_sound 函数要求:传入的对象必须是 Animal 类型(或其子类)
def make_sound(animal:Animal):
    animal.speak()

a1 = Animal()
d1 = Dog()
c1 = Cat()

# 下面就是多态的体现
make_sound(a1) # 动物正在发出声音
make_sound(d1) # 汪汪汪!
make_sound(c1) # 喵喵喵!

# 按标准多态规则:Pig 没有继承 Animal,类型不匹配(会出现类型警告)
p1 = Pig()
make_sound(p1)  # 在其它语言中会报错,虽然 Python 中能运行,但这不属于标准多态

鸭子多态

鸭子多态(Duck Typing):指一种编程风格,它并不依靠查找对象类型来确定其是否具有正确的接口,而是直接调用或使用其方法或属性(“看起来像鸭子,叫起来也像鸭子,那么肯定就是鸭子。”)

官方文档地址:https://docs.python.org/zh-cn/3.13/glossary.html#term-duck-typing

class Dog:
    def speak(self):
        print('汪汪汪!')

class Cat:
    def speak(self):
        print('喵喵喵!')

class Pig:
    def speak(self):
        print('哼哼哼!')

# make_sound 函数不在限制入参类型
def make_sound(animal):
    animal.speak()

d1 = Dog()
c1 = Cat()
p1 = Pig()

# 下面就是多态的体现
make_sound(d1) # 汪汪汪!
make_sound(c1) # 喵喵喵!
make_sound(p1)  # 哼哼哼!

抽象类

概念:抽象类(Abstract Class)是指不能被直接实例化、主要用于定义接口的类,它通常包含一个或多个抽象方法(只有声明而没有具体实现的方法)。子类必须实现这些抽象方法才能被实例化。

定义:Python 通过内置的 abc 模块(Abstract Base Classes)来支持抽象类和抽象方法的定义。具体步骤如下:

1. 导入 ABC 和 abstractmethod

从 abc 模块导入 ABC 类(作为抽象类的基类)和 abstractmethod 装饰器。

2. 定义抽象类

创建一个继承自 ABC 的类,并用 @abstractmethod 装饰需要子类强制实现的方法。

3. 实例化限制

如果子类没有实现所有抽象方法,则子类本身也是抽象类,无法被实例化。

4. 普通方法

抽象类不仅可以包含抽象方法,也可以包含普通方法(即非抽象方法,带有具体实现)。这些具体方法会被子类继承,并且可以直接使用,无需子类重写。

实例代码:

from abc import ABC, abstractmethod

class MustRun(ABC):
    @abstractmethod
    def run(self):
        pass

    def test(self):
        print("test method called")

class Person(MustRun):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def run(self):
        print(f"run method called {self.name} with age {self.age}")

p1 = Person("P1", 20)
p1.run()
p1.test()

# m1 = MustRun() # 直接实例化抽象类运行时会报错

内存分析

内存分为两个部分:栈内存、堆内存;变量在栈内存中,对象在堆内中。

Python 中变量里保存的不是数据,而是指向堆内存中对象的引用(内存地址)。

不可变对象:重新赋值会创建对象。

int 类的实例对象,时不可变对象,所以修改变量 a 时,会创建新对象,不会影响其他引用 b。

Python 中常见不可变对象有:int、float、bool、str、tuple、frozenset、None。

Python 中常见的可变对象有:list、dict、set、自定义类的实例对象。

可变对象:修改内容不改变地址。

自定义类对象的内存表示。

声明:本文为原创文章,51blog.xyz和作者拥有版权,如需转载,请注明来源于51blog.xyz并保留原文链接:https://mp.51blog.xyz/article/115.html

文章归档

推荐文章

buildadmin logo
Thinkphp8 Vue3 Element PLus TypeScript Vite Pinia

🔥BuildAdmin是一个永久免费开源,无需授权即可商业使用,且使用了流行技术栈快速创建商业级后台管理系统。

热门标签

PHP ThinkPHP ThinkPHP5.1 Go Mysql Mysql5.7 Redis Linux CentOS7 Git HTML CSS CSS3 Javascript JQuery Vue LayUI VMware Uniapp 微信小程序 docker wiki Confluence7 学习笔记 uView ES6 Ant Design Pro of Vue React ThinkPHP6.0 chrome 扩展 翻译工具 Nuxt SSR 服务端渲染 scrollreveal.js ThinkPHP8.0 Mac webman 跨域CORS vscode GitHub ECharts Canvas vue3 three.js 微信支付 PHP全栈开发 Python AI 人工智能 AI生成 工作经验 实战笔记