【零基础学Python】08-Python面向对象之封装、多态和函数进阶

文章目录:

一、前言

老铁们,上一期我们认识了,什么是面向对象,以及封装的使用,那么本期我们将继续介绍面向对象的继承和多态的特性,以及我们函数的进阶使用。

二、继承

1、什么是继承

继承字面意思就是子承父业,也就是说你父中有的我子类中也可以使用。

我们的继承分为两种:

  • 单继承
  • 多继承

继承这个概念,在我们的程序中,用于描述多个类之间的所属关系

比如,我们有一个B类,这个B类继承了A类之后,那么此时我们的B类叫做子类,A类叫做父类。

同时,B类中可以拥有A类中的所有属性和方法(包括,实例属性、类属性、示例方法、类方法)

2、单继承的基本使用

继承的核心就是提高我们代码的复用率,而且我们可以进行自定义扩展。

单继承的语法:

class 子类(父类):

示例:

py 复制代码
class Animal:
    # 类属性
    dec = '动物'

    # 类方法
    @classmethod
    def run(cls):
        print(cls.dec ,'正在跑')

    # 对象属性
    def __init__(self, name):
        self.name = name

    # 对象方法
    def call(self):
        print(self.name, '正在叫')


# 给动物写一个子类,就是我们的猫和狗
# 那么,猫和狗有我们的叫、跑等行为,这些行为我们直接继承父类中使用就行
# 无需重复的定义我们的这些行为
# 继承的语法: class 子类(父类名)


# 子类:狗
class Dog(Animal):
    pass

class Cat(Animal):
    pass

dag = Dog('小狗')
dag.run()
dag.call()
print('---'*100)
cat = Cat('小猫')
cat.run()
cat.call()

结果:

3、多继承的基本使用

对于所有父类中的属性和方法不重名的情况下是不影响互相使用的

多继承的使用语法:只需要在我们的括号里面写你要继承的所有父类就行了

class 子类名(父类1,父类2...)

示例:

py 复制代码
class A:
    a = 19
    def a_fun(self):
        print('我是a类中的方法')

class B:
    b = 18
    def b_fun(self):
        print('我是b类中的方法')

class C(A, B):
    pass

c = C()
c.a_fun() # 我是a类中的方法
c.b_fun() # 我是b类中的方法

结果:

4、多继承的父类属性方法重名

我们在继承的时候,如果这个子类的多个父类中的属性和方法重名会怎么样呢?

1)如果多个父类中有相同的属性和方法,那么我们具体使用的是我们第一个继承的父类中的属性和方法

py 复制代码
class A:
    money = 100
    def fun(self):
        print('我是A类中方法')

class B:
    money = 200
    def fun(self):
        print('我是B类中的方法')

# A类和B类中的属性和方法重名,那么现在我们要使用C类去继承这两个类
class C(A, B):
    pass

c = C()
print(c.money) # 100
# 调用的是A类中的方法
c.fun() # 我是A类中方法

2)如果想要使用指定父类中的属性和方法,那么我们只需要调换多继承的顺序即可。

py 复制代码
class A:
    money = 100
    def fun(self):
        print('我是A类中方法')

class B:
    money = 200
    def fun(self):
        print('我是B类中的方法')

# A类和B类中的属性和方法重名,那么现在我们要使用C类去继承这两个类
class C(B, A):
    pass

c = C()
print(c.money) # 200
# 调用的是B类中的方法
c.fun() # 我是B类中方法

那么出现多继承父类属性或者方法同名的时候我们是怎么去看你的继承顺序的呢?

通过类名.__mro__魔法属性

示例:

py 复制代码
print(C.__mro__)
# 结果:(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

5、继承-重写父类中的方法

当我们的子类中有父类中相同的属性或者方法时,我们优先使用的是子类的相同属性和方法。

示例:

py 复制代码
class A:
    money = 100

    def use_money(self):
        print('我是父类中的方法')

class B(A):
    # 覆盖父类中的money方法
    money = 500

    # 重写父类中的money方法
    def use_money(self):
        print('我是子类中的方法')

# 实例化一个子类对象
b = B()
print(b.money) # 使用的是子类中的500
b.use_money() # 调用的是子类中的方法

6、子类重写父类中属性或者方法调用父类

当发生继承的时候,子类中重写的父类的属性和方法,此时我们优先调用的是子类的属性和方法,那么我们如何做到调用父类的属性和方法呢?

也就是说:重名的情况下,你默认用的是子类的,但是我现在的需求是我不用子类的,我要用父类的。

语法: 使用super()调用子类与父类重名属性或者方法。

注意: 这个方法需要在我们类中的方法中使用

示例:

py 复制代码
class A:

    def use_money(self):
        print('我是父类中的方法')

class B(A):


    # 重写父类中的money方法
    def use_money(self):
        print('我是子类中的方法')

    def use_super(self):
        # 在此处调用父类中的方法
        super().use_money() # 此时此处就是我们的父类中的use_money方法

# 实例化一个子类对象
b = B()
b.use_super()

三、多态

多态呢,这里面有个经典的例子,我们称之为鸭子类型。如果有一只鸟走起来像鸭子,叫起来也像鸭子,甚至连吃饭睡觉都像鸭子,那么这只鸟就叫鸭子。

也就是说多态的本质:我们忽略实际的形态,而是以胜任的方式去充当该类型。你的行为像某个东西,那么就是某一个东西,你这只鸟的行为像鸭子,你就是鸭子。

定义某一个行为,这个行为出现在不同的对象身上有不同的表现形式,或者同一个类创建的对象他可以有不同的身份,这些就是多态的表现(学过Java的老铁可能对于多态了解会比较熟悉一点)

多态是在继承的基础上才会发生的,所以多态的一个前提条件你得有继承:

示例:

py 复制代码
class Animal:
    # 动物有叫的行为
    def speak(self):
        print('动物在叫')


class Dog(Animal):
    # 狗狗有自己的行为
    def speak(self):
        print('狗在汪汪叫!')

class Cat(Animal):
    # 猫咪有自己的行为
    def speak(self):
        print('猫在喵喵叫!')

# 怎么实现多态呢?我们在此处写一个方法调用speak的行为
def use_speak(animal):
    animal.speak()

# 实例化对象
dog = Dog()
cat = Cat()

use_speak(dog) # 狗在汪汪叫!
use_speak(cat) # 猫在喵喵叫!

四、函数进阶

1、匿名函数

匿名函数就是我们的函数可以没有名字也可以有,使用lambda进行定义。

核心作用就是简化函数定义的语法格式。

1.1 没有名字的匿名函数

语法:

lambda 形参1,形参2,...,形参n:返回值

调用: 将匿名函数整体括起来,然后直接在匿名函数后面加上括号传递实参即可

(lambda 形参1,形参2,...,形参n:返回值)(传递参数调用)

示例:

py 复制代码
# 函数定义
lambda x, y: x + y


# 调用:直接将整个匿名函数括起来,然后直接在后面加一个括号传递实参
print((lambda x, y: x + y)(10, 20))

1.2 有名字的匿名函数

给匿名函数取一个名字进行调用:就是首先将这个匿名函数赋值给一个变量,这个变量我们称之为函数对象,然后通过函数对象的名字后面跟个括号来传递实参,然后进行一个匿名函数的调用

示例:

py 复制代码
# 有名字的匿名函数
func = lambda x, y: x + y
print(func(10, 30))

匿名函数,它存在的主要意义就是完成函数定义和调用的简化步骤逻辑。

2、函数的闭包操作

2.1 闭包的含义

  • 所谓的闭包就是我们在定义一个函数的时候,嵌套了另外一个函数,被嵌套的函数我们称之为内部函数
  • 然后我们内部函数使用了外部函数的变量
  • 并且外部函数返回了内部函数的名字(也就是函数引用)

2.2 函数的引用可以进行传递(函数对象赋值)

什么意思呢?就是说:我们函数的功能是可以进行传递的,我可以把我的功能传授给你,说白了,函数引用是可以赋值的,好比就是函数名里面是一个地址,那么这个地址是可以赋值给其他变量的。函数名本质上就是一个 "地址 / 引用"

语法: 变量名 = 函数名

具体的解释,我们看如下例子:

py 复制代码
def func(name):
    print(f'我的名字是:{name}')



# 首先你要知道,我们的函数名是存地址的,这个地址指向我们函数体
print('func的地址:', func) # <function func at 0x0000024B298104A0>
# 将func这个地址赋值给我们的其他变量,那么其他变量也是指向这个地址了
tmp_func = func
print('tmp_func的地址:', tmp_func) # <function func at 0x0000024B298104A0>
func('谈简特') # 我的名字是:谈简特
tmp_func('谈简特') # 我的名字是:谈简特

解释:

3、构造函数的闭包结构

注意闭包的条件:

  • 外层函数嵌套一个内层函数
  • 内存函数使用了外层函数的变量
  • 外层函数返回内层函数的引用

示例:

py 复制代码
# 外层函数
def out_func(num1):
    # 内层函数
    def inner_func(num2):
        # 内层函数中使用外层函数的变量
        print(f'num1 + num2 = {num1 + num2}')

    # 外层函数返回内层函数的引用(函数名)
    return inner_func

直接调用内层函数会报错:

py 复制代码
# 直接调用内层函数就会报错:NameError: name 'inner_func' is not defined
inner_func(10)

原因:

如何解决? 逻辑如下:

代码:

py 复制代码
# 外层函数
def out_func(num1):
    # 内层函数
    def inner_func(num2):
        # 内层函数中使用外层函数的变量
        print(f'num1 + num2 = {num1 + num2}')

    # 外层函数返回内层函数的引用(函数名)
    return inner_func


# 我们可以先调用我们的外层函数来间接的实现内层函数的调用
func = out_func(10) # 将内层函数的引用返回给func
func(20) # func就直接等价于是内层函数了

零基础学习Python贵在坚持,代码实操是夯实知识点最快的方式,本篇梳理了面向对象继承、多态与lambda、闭包核心用法。

文章有用欢迎点赞收藏,专栏持续更新Python与软件测试干货,不足之处欢迎评论指正。

相关推荐
人道领域2 小时前
一篇文章解决Codex的安装,实操一遍过
java·开发语言·codex
thisiszdy2 小时前
<C++> 智能指针
开发语言·c++
fox_lht3 小时前
第十四章 一个输入和输出项目:构建一个命令行程序
开发语言·后端·rust
专注VB编程开发20年3 小时前
工控上位机开发为什么固死.net 4.5.2sdk?适配win7
python·信息可视化·c#
郑州光合科技余经理3 小时前
海外版外卖系统:如何快速搭建国际化外卖平台
java·开发语言·前端·人工智能·小程序·系统架构·php
Cheng小攸3 小时前
协议分析与分析工具(一)
开发语言·php
CC数学建模3 小时前
2026第八届中青杯全国大学生数学建模竞赛C题:情绪维度耦合约束的脑电信号情绪识别 (1)完整思路、代码、模型、文章,全网首发高质量分享!
python·算法·数学建模
fox_lht3 小时前
14.2.读文件
开发语言·后端·rust
codeejun3 小时前
每日一Go-74、Go 云原生可观测性实战之OpenTelemetry 全链路采集:Trace + Metrics + Logs
开发语言·云原生·golang