Python知识学习07

第一部分:Python 函数进阶知识点

01. 参数的传递方式

1.1 分析代码执行结果

观察下面的代码,说明位置 1 和位置 2 的输出结果,并解释为什么?

  • 位置 1:800 ["hello"]

  • 位置 2:800 ["hello", "world"]

  • 原因:整数是不可变数据、列表是可变数据;本质是内存地址传递导致的差异

    声明两个全局变量

    a = 800
    b = ["hello"]

    声明一个函数

    def fn(x, y):
    """通过x,y修改数据"""
    x = 1000
    y.append("world")

    print(a, b) # 位置1

    调用函数修改 数据

    fn(a, b)
    print(a, b) # 位置2

1.2 内存参数传递模型

① 声明变量,内存申请空间,将内存地址赋值给变量

声明了 a, b 变量,内存中会申请空间,分别存储对应的数据,并且将存储数据的内存地址分别赋值给 a, b

② 函数传参:实际参数把内存地址传递给形式参数

调用函数 fn () 时,通过函数调用语法,将 a, b 实际参数的数据,传递给 x, y 形式参数,内存中是将 a, b 的内存地址传递给了形式参数 x, y;所以可以通过 x 访问 a 的数据,可以通过 y 访问 b 的数据

③ 修改变量:

  • 不可变类型(int/str/tuple):重新赋值 = 新地址,不影响外部

  • 可变类型(list/dict):修改内部数据 = 直接改原地址内容,影响外部

函数内部通过变量x, y修改数据时,内存中发生了如下的操作

小总结

  • 函数参数传递本质:传递内存地址(引用传递)

  • 可变类型参数:函数内修改会影响外部

  • 不可变类型参数:函数内修改不影响外部

1.3 总结 - 关于值 / 引用传递

复制代码
# 声明两个全局变量
a = 800
b = ["hello"]

def fn(x, y):
    x = 1000
    y = ["hello", "world"]   # 重新赋值新列表
    
print(a, b)   # 位置1:800 ["hello"]
fn(a, b)
print(a, b)   # 位置2:800 ["hello"]

重要结论

  • Python 中只有引用传递,没有值传递

  • 对形参整体重新赋值,无论可变 / 不可变,都不会影响外部实参

02. 函数递归

2.1 认识递归

  • 递归:函数内部调用自身

  • 必须有终止条件,否则无限递归崩溃

  • 适合:有重复子问题的逻辑(阶乘、斐波那契)

基本语法

复制代码
def 函数():
    # 函数内部包含多行代码
    # 内部调用了自己 - 调用过程 - 递归
    函数()

递归特点:

函数封装了多行代码,表示了一个业务的执行流程

函数内部调用自身,就是一种业务流程的重复执行,相当于循环执行,是一整套 / 整个函数 代码复用!

用户名校验案例

复制代码
def reg_username():
    username = input("请输入账号(长度6~12):")
    if not 6 <= len(username) <= 12:
        input("账号长度不合法,按任意键重新输入")
        return reg_username()  # 递归
    print("合法账号:", username)

reg_username()

2.2 递归经典案例

递归的好处

递归,能让重复的业务流程,编写代码的时候更加容易理解和编写

(1)斐波那契数列
复制代码
def fib(n):
    if n == 1 or n == 2:
        return 1
    return fib(n-1) + fib(n-2)
(2)阶乘计算
复制代码
def fac(n):
    if n == 1:
        return 1
    return n * fac(n-1)

2.3 递归总结

递归 (Recursion) 是一个非常高级的语法,让包含一定规则的业务逻辑,编写代码的时候更加容易理解和编码;但是递归的底层执行逻辑决定了它会大量消耗内存空间,所以在脚本编写 / 应用开发的时候一定要慎重使用

常规规范:单层递归 (函数内部只调用自己一次),递归次数不建议超过 10 次

项目组规范:很多项目组为了避免递归造成的问题,直接规范中要求禁止使用递归 (造成的问题很难查询)!

Python 中,可以通过编码实现对递归层次的控制

注意:系统中可以设置递归次数,但是一般很少修改

原因:限制递归次数是为了显示开发人员;Python 内建模块中也使用了大量的递归,如果修改为 10 次递归次数的话,编写的大量脚本 (包含了其他模块) 都会报错!

复制代码
>>> import sys
>>> sys.getrecursionlimit()
1000
>>>
>>>
>>> sys.setrecursionlimit(10)
>>> sys.getrecursionlimit()
10

03. 函数闭包

3.1、 问题分析

需求:某公司员工小张,开发了自己的脚本库,但是最近脚本运行出现了一些问题,需要对脚本中的函数进行监控,记录函数执行的状态、记录函数执行的时间;

复制代码
# 小张脚本
def serv_01():
    # 记录开始状态、开始时间
    print("serv_01处理功能")
    # 记录结束状态,结束时间
    # 计算总耗时

def serv_02():
    print("serv_02处理功能")

def serv_03():
    print("serv_03处理功能")

def serv_04():
    print("serv_04处理功能")


serv_01()
serv_02()
serv_03()
serv_04()

3.2、 解决方案

常规解决方案,就是逐个函数进行编码

  • 事情紧急的情况下,没有更好的方案,手工操作也是一种折中的方案!先动起来!

    小张脚本

    import time
    def serv_01():
    start = time.time()
    print("记录开始状态")
    print("serv_01处理功能")
    time.sleep(0.5)
    print("记录结束状态")
    print(f"总耗时:{time.time() - start}ms")

    def serv_02():
    print("serv_02处理功能")

    def serv_03():
    print("serv_03处理功能")

    def serv_04():
    print("serv_04处理功能")

    serv_01()
    serv_02()
    serv_03()
    serv_04()

3.3 认识闭包

闭包 = 外部函数 + 内部函数 + 内部使用外部变量

  • 延长局部变量生命周期

  • 不修改原函数,实现功能扩展

基本语法

复制代码
def outer():
    """外部函数"""
    msg = "外部函数局部变量"
    
    def inner():
        """内部函数:闭包函数"""
        print("msg:", msg)
       
    # 返回内部函数的引用
    return inner

闭包特点

  • 函数内部声明的函数

  • 内部函数使用了外部函数的局部变量

  • 外部函数最后返回了内部函数的引用

闭包作用

  • 延长局部变量作用域,让局部变量不再局限于一个函数内部

    • 局部变量:局部变量只能在当前函数内部访问,当前函数执行完成,局部变量立即销毁

    • 闭包 - 局部变量在函数执行期间被保留,可以在函数外部访问局部变量

  • 闭包可以在不修改目标函数的情况下,给函数添加新的功能

    • 闭包的一种特殊语法:称为装饰器

3.4 闭包应用:装饰器

装饰器 = 闭包的经典应用,无侵入式增强函数

装饰器语法

复制代码
def  装饰器名称(fn):
    """参数fn,是一个函数类型,表示目标函数"""
    def wrapper():
        print("目标函数执行之间添加的功能")
        # 执行目标函数
        fn()
        print("目标函数执行之后添加的功能")
    return wrapper

@装饰器名称
def serv_01():
    print("执行serv_01功能")
    
serv_01()

装饰器应用

复制代码
import time
def timer(fn):
    """给目标函数计时的装饰器"""
    def wrapper():
        # 记录开始时间
        start = time.time()
        # 执行目标函数
        fn()
        # 记录结束时间
        end = time.time()
        print(f"总耗时:{end -start}ms")
    return wrapper

def status(fn):
    """记录状态装饰器"""
    def wrapper():
        print("开始执行")
        fn()
        print("执行完毕")
    return wrapper

import time
# 小张脚本
# serv_01函数,添加了计时、记录状态功能
@status
@timer
def serv_01():
    time.sleep(0.5)
    print("serv_01处理功能")

# serv_02函数,添加了计时功能
@timer
def serv_02():
    print("serv_02处理功能")

# serv_03函数,添加了记录状态的功能
@status
def serv_03():
    print("serv_03处理功能")

def serv_04():
    print("serv_04处理功能")


serv_01()
print("-------------------------")
serv_02()
print("-------------------------")
serv_03()
print("-------------------------")
serv_04()

3.5、 闭包的另一个作用

小红打车,3 公里内 8 元;超过 3 公里每公里 2 元,如果停车等待每分钟 1.5 元;

下面是小红的行程:行驶了 5 公里、等 1 分钟红灯、行驶 2 公里、堵车等待 8 分钟;继续行驶 4 公里到达目的地;

① 使用传统语法,编写代码实现,通过全局变量实现

复制代码
total = 0  # 总价格

def texi(k=0, t=0):
    """计费价格,k公里数,t分钟数"""
    global total
    # 此处编写代码.....
    
texi(k=5)
texi(t=1)
texi(k=2)
texi(t=8)
texi(k=4)
print("总费用:", total)

② 使用闭包语法,通过局部变量记录总费用 (闭包 - 延伸了局部变量作用范围)

复制代码
def texi(k=0, t=0):
    """计费价格,k公里数,t分钟数"""
    total = 0  # 记录总费用
    # 此处编写代码
    ...
    
c = texi()
c(k=5)
c(t=1)
c(k=2)
c(t=8)
money = c(k=4)
print("总费用:", money)

04. 匿名函数(lambda 表达式)

4.1、 认识匿名函数

匿名函数:就是表示一种没有名称的函数,在大部分的编程语言中都有对应的实现

  • 如:JavaScript 语法,提供了一种箭头函数的语法,就是一种匿名函数

javascript

运行

复制代码
// 匿名函数,也称为箭头函数
let add = (x, y) => x + y

// 等价于
function add(a, b){
    return a + b
}

Python 中也提供了一种匿名函数的实现,主要通过lambda 关键字声明的表达式 (简称为 lambda 表达式)

python

运行

复制代码
# 1. 普通函数
def addition(a, b):
    return a + b


# 2. 匿名函数:等价与前面的普通函数
# lambda表达式
addition2 = lambda x, y : x + y

print(addition(11, 22))
print(addition2(11, 22))

4.2、 lambda 表达式

基础语法:

python

运行

复制代码
存储表达式的变量  = lambda 参数列表: 返回一个数据的表达式

代码示例:

python

运行

复制代码
# 计算加法运算的表达式
addition = lambda x, y : x + y

# 根据传递的整数数据,返回性别描述
# 0 - 女,1 - 男
gender = lambda n : "男" if n == 1 else "女"

表达式作用:

  • 简化只包含一行代码的函数,通过表达式简化代码,提高代码的可读性

4.3、 lambda 表达式 & 高级函数

需求 1:需要对列表中的整数数据进行排序

复制代码
lst = [12, 39, 19, 41, 32, 47, 36, 42, 25, 37, 16, 31, 17, 10, 23, 33, 35, 40, 22, 30]

def sort_fn(x):
    return -x
# 指定自定义排序方案
lst.sort(key=sort_fn)

print(lst)

# lambda表达式优化
lst = [12, 39, 19, 41, 32, 47, 36, 42, 25, 37, 16, 31, 17, 10, 23, 33, 35, 40, 22, 30]
# 指定自定义排序方案
lst.sort(key=lambda x: -x)
print(lst)

需求 2:对集合中记录的账号进行过滤,将符合条件的账号收集起来

复制代码
# 账号收集 6~12位
accounts = {
    "damu", "xiaoli", "admin", "root",
    "manager", "administrator", "honghh",
    "ljh", "www", "qqy", "chunyang"
}
# 传统
def check_account(account):
    val_account = set()
    for i in account:
        if 6 <= len(i) <= 12:
            val_account.add(i)
    return val_account

print("有效的账号:", check_account(accounts))

# lambda表达式,结合高阶函数filter()
# filter(参数1,参数2)
# 参数1:条件函数,函数返回结果为True表示这个数据保留
# 参数2:序列数据,将序列数据进行遍历,遍历到的每个数据交给参数1的函数进行验证
val_account = set(filter(lambda x: 6 <= len(x) <= 12, accounts))
print(val_account)

需求 3:计算 0~100 的和

复制代码
def sum(start, end):
    """总和"""
    total = 0
    for i in range(start, end + 1):
        total += i
    return total

print(sum(0, 100))

# lambda表达式、结合reduce()高阶函数(累加)
from functools import reduce

# reduce(参数1,参数2)
# 参数1:是一个累加函数
# 参数2:是一个序列数据,自动遍历序列数据,将每个数据交给参数1累加
sum = reduce(lambda x, y: x + y, range(0, 101))
print(sum)

05. 偏函数

5.1、 实际需求

需求:某公司小李开发了一个功能函数,可以将目标数据转换成对应的进制

复制代码
def covert_num(x, base):
    """进制 转化"""
    if base == 2:
        return bin(x)
    elif base == 8:
        return oct(x)
    elif base == 16:
        return hex(x)
    else:
        return "没有这个进制"

print(covert_num(10, 16))
print(covert_num(8, 2))
print(covert_num(255, 2))
print(covert_num(19, 8))

上述代码的功能性正常,但是企业要求更高:

  • 问题 1:每次转换进制,都需要手工输入对应的进制,调用麻烦

  • 问题 2:每次调用这个函数,需要了解一下参数的含义才能明确要传递什么数据

  • 问题 3:函数使用的时候,2 进制转换比较多的,其他进制转换比较少;2 进制转换也需要传递 base=2 比较麻烦

5.2、 认识偏函数

解决问题 3:对于经常使用 2 进制转换,可以通过函数参数的默认值进行解决

复制代码
def covert_num(x, base=2):
    """进制 转化"""
    if base == 2:
        return bin(x)
    elif base == 8:
        return oct(x)
    elif base == 16:
        return hex(x)
    else:
        return "没有这个进制"

print(covert_num(10, 16))
print(covert_num(8)) # 默认转换2进制
print(covert_num(255,)) # 默认转换2进制
print(covert_num(19, 8))

对于问题 1 和问题 2:需要将函数进行改造才能实现

  • 手工封装多个函数,实现对原有函数的扩展!

    def covert_num(x, base):
    pass

    def covert_num_2(x):
    return covert_num(x, base=2)
    def covert_num_8(x):
    return covert_num(x, base=8)
    def covert_num_16(x):
    return covert_num(x, base=16)

    print(covert_num_16(10))
    print(covert_num_2(8)) # 默认转换2进制
    print(covert_num_2(255,)) # 默认转换2进制
    print(covert_num_8(19))

功能:偏函数,解决函数调用多样性的问题,通过给函数添加额外的参数,解决函数的可用性、可读性!

复制代码
# 偏函数的扩展
from functools import partial

covert_num_2 = partial(covert_num, base=2)
covert_num_8 = partial(covert_num, base=8)
covert_num_16 = partial(covert_num, base=16)

print(covert_num_16(10))
print(covert_num_2(8)) # 默认转换2进制
print(covert_num_2(255,)) # 默认转换2进制
print(covert_num_8(19))

如果用 lambda 表达式改造?

  • 原本的转换代码:covert_num_16 = partial (covert_num, base=16)

  • lambda 表达式:covert_num_16 = lambda x: covert_num (x, base=16)

第二部分:Python 面向对象编程(OOP)基础

1 认识面向对象编程思想

1.1 问题引入:从生活场景理解编程思想

通过 "与女朋友爬山"的场景对比,直观理解两种编程思想的核心差异:

场景特点 核心逻辑 优点 缺点 对应编程思想
风雨无阻爬山,不受额外事情影响 关注爬山流程本身,步骤固定 稳定性好 扩展性差(无法灵活应对变化) 面向过程
可灵活调整计划(换早餐店、新增跑步) 关注参与对象(你、女朋友)的需求与交互 扩展性好 稳定性较差(需额外协调变化) 面向对象

1.2 核心概念:什么是面向对象

1.2.1 思想的本质

思想是对已发生问题即将发生问题的解决方案的指导,是经过大量实践归纳的解决问题的思路。

1.2.2 面向对象的定义
  • 本质 :站在对象的角度看待问题,模拟自然人解决问题的方式;

  • 核心逻辑 :通过参与问题解决的对象(事物) ,利用其自身的 特征(属性)行为(方法) 的协作,完成问题处理;

  • 核心价值:不仅能解决当前问题,还能通过对象的复用与扩展,应对更多场景需求。

1.3 面向过程 vs 面向对象

两种编程思想适配不同开发场景,对比如下:

对比维度 面向过程(POP) 面向对象(OOP)
核心关注 解决问题的过程和步骤 解决问题的对象、属性与行为
语法实现 函数式编程(通过函数定义步骤,函数间调用实现流程) 类和对象(通过类封装属性与方法,对象交互实现功能)
核心优势 系统稳定性极强 系统扩展性极强
核心劣势 系统扩展性极差 系统稳定性较差(需额外技术维稳)
适用场景 操作系统研发、小型固定脚本 电商平台、大型应用、需频繁迭代的项目
代表语言 C 语言(纯面向过程) Java(纯面向对象)、Python(支持两种思想)

2 类与对象的基础语法

类和对象是面向对象编程的核心载体类是抽象模板,对象是模板的具体实例

2.1 类的声明

通过 class 关键字自定义类型,封装对象的共同属性与方法,遵循固定编码规范。

2.1.1 基础语法与编码规范
复制代码
class 类名:  # 类名:多个英文单词组成,每个单词首字母大写(大驼峰命名)
    """类的文档注释:说明类的功能、用途(类内部第一行)"""
    
    # 1. 属性声明(后续详细讲解)
    # 2. 构造方法:初始化对象的成员属性(固定语法 __init__)
    def __init__(self, 形参1, 形参2, ...):
        """构造方法:创建对象时自动调用,用于初始化成员属性"""
        self.成员属性名1 = 形参1  # self 表示当前对象,绑定成员属性
        self.成员属性名2 = 形参2
    
    # 3. 方法声明(后续详细讲解)
    def 方法名(self, 形参...):
        """成员方法:对象的行为,第一个参数必须是 self"""
        代码逻辑
2.1.2 示例 1:声明 "主机" 类
复制代码
class Host:
    """主机类:封装主机的名称、IP地址等属性,提供信息获取方法"""
    
    def __init__(self, host_name, host_ip):
        """初始化主机的成员属性:主机名称、IP地址"""
        self.host_name = host_name  # 成员属性:主机名称
        self.host_ip = host_ip      # 成员属性:IP地址
    
    def get_info(self):
        """成员方法:获取主机完整信息"""
        return f"{self.host_name}: {self.host_ip}"
2.1.3 示例 2:声明 "用户" 类
复制代码
"""
用户类:封装用户账户信息,提供登录功能
"""
class User:
    def __init__(self, username, password):
        """初始化成员属性:用户名、密码"""
        self.username = username  # 成员属性:用户名
        self.password = password  # 成员属性:密码
    
    def login(self):
        """成员方法:用户登录验证(仅实现登录单一功能)"""
        if self.username == "admin" and self.password == "123":
            return True  # 登录成功
        return False  # 登录失败

2.2 对象的创建与使用

对象是类的具体实例,通过类名 + 括号创建,可访问自身属性和调用方法。

2.2.1 核心语法
  • 创建对象:对象引用变量 = 类名(实参1, 实参2, ...)(实参对应 __init__ 形参);

  • 访问成员属性:对象引用变量.成员属性名

  • 调用成员方法:对象引用变量.方法名(实参...)

  • 判断对象关系:is(是否为同一个对象)、isinstance(对象, 类名)(是否属于某个类)。

    语法:对象引用变量 = 类名称(实参1, 实参2, ...)

    admin_user = User("admin", "123") # 创建用户对象

2.2.2 示例:创建主机对象并操作
复制代码
if __name__ == '__main__':
    # 1. 创建主机对象(自动调用 __init__ 方法)
    host100 = Host("host100", "192.168.0.100")
    host101 = Host("host101", "192.168.0.101")
    
    # 2. 打印对象(输出内存地址,证明对象是独立的实体)
    print(host100)
    print(host101)
    
    # 3. 访问成员属性
    print(host100.host_name)
    print(host101.host_ip)
    
    # 4. 调用成员方法
    print(host100.get_info())
    print(host101.get_info())
    
    # 5. 判断对象关系
    print(host100 is host101)
    print(isinstance(host100, Host))
    print(isinstance(host101, Host))

2.3 类和对象的核心关系

对比维度 类(Class) 对象(Object)
本质 自定义类型,抽象模板(逻辑上的概念) 类的具体实例,实际存在的实体(物理上的概念)
特征 包含共同属性名和共同方法名,无具体数据 包含具体属性值和可执行方法,数据独立
关系 一个类可创建多个对象(一对多) 一个对象仅属于一个类(多对一)
生活类比 "人""电脑""动物"(事物的统称) 屈真、某品牌电脑、某只小狗(具体事物)

2.4 实战任务

需求:声明 "文件" 类(包含文件名称、文件路径、文件属性),创建 "软连接文件 python3.12" 的对象。

复制代码
class File:
    """文件类:封装文件的名称、路径、属性"""
    
    def __init__(self, file_name, file_path, file_attr):
        """初始化文件属性:名称、路径、属性"""
        self.file_name = file_name  # 成员属性:文件名称
        self.file_path = file_path  # 成员属性:文件路径
        self.file_attr = file_attr  # 成员属性:文件属性(如"软连接""普通文件")
    
    def get_file_info(self):
        """获取文件完整信息"""
        return f"文件名称:{self.file_name}\n文件路径:{self.file_path}\n文件属性:{self.file_attr}"

# 创建软连接文件对象
soft_link_file = File("python3.12", "/usr/bin/python3.12", "软连接文件")
# 访问对象信息
print(soft_link_file.get_file_info())

3 标准类结构与案例

3.1 标准类结构

Python 中标准、完整的类结构包含:类属性、构造方法、实例方法、类方法、静态方法

复制代码
class 类名:
    # 类属性
    属性 = 值
    
    # 构造方法
    def __init__(self, 参数):
        self.实例属性 = 参数
    
    # 实例方法
    def 方法(self):
        pass
    
    # 类方法
    @classmethod
    def 类方法(cls):
        pass
    
    # 静态方法
    @staticmethod
    def 静态方法():
        pass

3.2 学生类案例

复制代码
class Student:
    school = "成都文理学院"  # 类属性
    
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        self.score = score
    
    def show_info(self):
        print(f"{self.name} {self.age}岁 {self.score}分")
    
    @classmethod
    def change_school(cls, new_school):
        cls.school = new_school
    
    @staticmethod
    def is_pass(score):
        return score >= 60

3.3 对象创建与使用

复制代码
# 创建对象
stu1 = Student("张三", 18, 85)
# 调用实例方法
stu1.show_info()
# 调用类方法修改学校
Student.change_school("成都大学")

四、面向对象三大特性

4.1 封装

4.1.1 封装的核心概念

  • 定义:隐藏对象内部的实现细节,只对外提供公开的访问接口(方法)

  • 作用:保护数据安全、避免外部随意修改、规范数据操作方式

  • 核心语法 :使用双下划线 __ 定义私有属性 / 方法,外部无法直接访问

4.1.2 私有属性与私有方法

  • 私有属性:self.__属性名 = 值

  • 私有方法:def __方法名(self):

  • 访问规则:类内部可以访问,类外部无法直接访问 / 修改,必须通过类提供的公开方法操作

4.1.3 案例:银行账户封装

复制代码
class BankAccount:
    def __init__(self, balance=0):
        self.__balance = balance  # 私有属性:账户余额,外部无法直接修改

    # 公开方法:存款
    def deposit(self, money):
        if money > 0:
            self.__balance += money
            print(f"存款成功,当前余额:{self.__balance}")
        else:
            print("存款金额无效!")

    # 公开方法:取款
    def withdraw(self, money):
        if 0 < money <= self.__balance:
            self.__balance -= money
            print(f"取款成功,当前余额:{self.__balance}")
        else:
            print("取款金额无效或余额不足!")

    # 公开方法:查询余额
    def get_balance(self):
        return self.__balance

# 测试封装
if __name__ == '__main__':
    account = BankAccount(1000)
    account.deposit(500)    # 存款
    account.withdraw(300)   # 取款
    print(account.get_balance())  # 查询余额
    # print(account.__balance)  # 报错:外部无法访问私有属性

4.1.4 封装的优点

  1. 数据安全:防止外部非法修改私有属性

  2. 代码规范:统一通过方法操作数据,便于维护

  3. 简化使用:外部无需关注内部实现,只需调用公开接口

4.2 继承

4.2.1 继承的核心概念

继承是面向对象三大特征之一,核心价值是代码复用功能扩展,允许子类(派生类)复用父类(基类)的属性和方法,同时添加自身独有的属性和方法。

  • 子类继承父类,复用代码

  • super() 调用父类方法

  • 支持多继承(谨慎使用)

4.2.2 概念与专业术语

术语 定义 示例
父类(基类 / 超类) 被继承的类,封装了子类的共同属性和方法 Person 类(封装 "姓名、年龄" 等共同属性)
子类(派生类) 继承父类的类,可复用父类资源,也可扩展自身资源 Student 类(继承 Person,新增 "成绩" 属性)
继承 子类获取父类属性和方法的过程 class Student (Person): 表示 Student 继承 Person
派生 子类在继承父类的基础上,新增属性或方法的过程 Student 类新增 study () 方法,属于派生

4.2.3 继承的基础语法

4.2.3.1 单继承语法

单继承指子类仅继承一个父类,语法简洁、逻辑清晰,是企业开发的主流选择。

复制代码
# 父类(基类):封装共同属性和方法
class 父类名:
    def __init__(self, 父类属性1, 父类属性2, ...):
        self.父类属性1 = 父类属性1
        self.父类属性2 = 父类属性2

    def 父类方法(self):
        代码逻辑

# 子类(派生类):继承父类,可扩展自身属性和方法
class 子类名(父类名):
    def __init__(self, 父类属性1, 父类属性2, ..., 子类属性1, 子类属性2, ...):
        # 调用父类的构造方法,初始化父类属性(必须优先执行)
        super().__init__(父类属性1, 父类属性2, ...)
        # 初始化子类独有的属性
        self.子类属性1 = 子类属性1
        self.子类属性2 = 子类属性2

    # 子类独有的方法(派生)
    def 子类方法(self):
        代码逻辑

    # 可选:重写父类方法(覆盖父类逻辑)
    def 父类方法(self):
        新的代码逻辑
4.2.3.2 示例:单继承实战(学生继承自 "人")
复制代码
# 父类:Person(封装"人"的共同属性和方法)
class Person:
    def __init__(self, name, age):
        self.name = name  # 父类属性:姓名
        self.age = age    # 父类属性:年龄

    def eat(self):
        """父类方法:吃饭(所有人的共同行为)"""
        print(f"{self.name}({self.age}岁)在吃饭")

# 子类:Student(继承 Person,扩展学生独有属性和方法)
class Student(Person):
    def __init__(self, name, age, student_id, score):
        # 调用父类构造方法,初始化父类属性(name、age)
        super().__init__(name, age)
        # 子类独有属性:学号、成绩
        self.student_id = student_id
        self.score = score

    def study(self):
        """子类独有方法:学习(学生的特有行为)"""
        print(f"学号:{self.student_id},姓名:{self.name},成绩:{self.score} → 正在学习")

    def eat(self):
        """重写父类方法:学生的吃饭行为(覆盖父类逻辑)"""
        print(f"学生 {self.name}({self.age}岁)在学校食堂吃饭")

# 测试单继承
if __name__ == '__main__':
    # 创建学生对象
    stu = Student(name="张三", age=18, student_id="2024001", score=90)

    # 1. 访问父类属性
    print("姓名:", stu.name)
    print("年龄:", stu.age)

    # 2. 访问子类属性
    print("学号:", stu.student_id)
    print("成绩:", stu.score)

    # 3. 调用父类方法(已重写)
    stu.eat()

    # 4. 调用子类方法
    stu.study()
4.2.3.3 多继承语法

多继承指子类继承多个父类,语法为 class 子类名(父类1, 父类2, ...):,但因易导致逻辑混乱(如菱形继承问题),企业开发中尽量避免使用。

复制代码
# 父类1:Person(封装"人"的基础属性)
class Person:
    def __init__(self, name):
        self.name = name

    def eat(self):
        print(f"{self.name} 在吃饭")

# 父类2:Worker(封装"工作者"的属性)
class Worker:
    def __init__(self, job):
        self.job = job

    def work(self):
        print(f"{self.name} 的工作是 {self.job}")

# 子类:Teacher(继承 Person 和 Worker)
class Teacher(Person, Worker):
    def __init__(self, name, job, subject):
        # 调用多个父类的构造方法
        Person.__init__(self, name)
        Worker.__init__(self, job)
        # 子类独有属性:教授科目
        self.subject = subject

    def teach(self):
        print(f"{self.name} 教授 {self.subject}")

# 测试多继承
teacher = Teacher(name="李四", job="教师", subject="Python")
teacher.eat()
teacher.work()
teacher.teach()

4.2.4 继承中的魔法属性与魔法方法(继承相关)

魔法属性和魔法方法是 Python 内置的特殊属性 / 方法(以 __ 开头和结尾),继承场景中常用以下几个:

4.2.4.1 常用魔法属性
魔法属性 功能 示例
__base__ 返回子类的直接父类(单继承) Student.base
__bases__ 返回子类的所有直接父类(多继承) Teacher.bases
__mro__ 返回子类的方法解析顺序(解决多继承冲突) Teacher.mro
4.2.4.2 常用魔法方法(继承相关)
魔法方法 功能 示例
__init__ 构造方法,初始化属性(子类需调用父类的 init super().init(name, age)
__str__ 字符串格式化方法,打印对象时返回友好信息 重写后 print (stu) 可输出学生详情
4.2.4.3 示例:重写 __str__ 魔法方法
复制代码
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

class Student(Person):
    def __init__(self, name, age, student_id):
        super().__init__(name, age)
        self.student_id = student_id

    def __str__(self):
        """重写 __str__ 方法,打印对象时返回友好信息"""
        return f"学生信息:[学号:{self.student_id},姓名:{self.name},年龄:{self.age}岁]"

# 测试
stu = Student(name="王五", age=19, student_id="2024002")
print(stu)

4.2.5 继承的核心优势与注意事项

4.2.5.1 核心优势
  • 代码复用:子类无需重复编写父类已有的属性和方法,减少冗余代码

  • 功能扩展:子类可在父类基础上新增属性和方法,或重写父类方法,适配特定需求

  • 逻辑清晰:通过继承建立类之间的层级关系,符合现实世界的分类逻辑

4.2.5.2 注意事项
  • 子类必须优先调用父类的构造方法(super().__init__),否则父类属性无法初始化

  • 多继承易导致方法名冲突,需通过 __mro__ 确认方法解析顺序,尽量避免使用

  • 继承层级不宜过深(建议不超过 3 层),否则会增加代码维护难度

4.3 多态

4.3.1 多态的核心概念

  • 定义一个接口,多种实现;不同子类对象调用同一个方法,执行不同的逻辑

  • 实现前提 :必须满足继承 + 方法重写两个条件

  • 核心作用:提高代码的通用性、扩展性和灵活性

4.3.2 多态的实现原理

  1. 子类继承同一个父类

  2. 子类重写父类的同一个方法

  3. 不同子类对象调用该方法,表现出不同的行为

4.3.3 基础案例:动物叫声(多态实现)

复制代码
# 父类:动物类
class Animal:
    def speak(self):
        """父类方法:定义统一接口"""
        pass

# 子类1:狗类(重写speak方法)
class Dog(Animal):
    def speak(self):
        print("汪汪汪")

# 子类2:猫类(重写speak方法)
class Cat(Animal):
    def speak(self):
        print("喵喵喵")

# 子类3:羊类(重写speak方法)
class Sheep(Animal):
    def speak(self):
        print("咩咩咩")

# 统一调用接口(多态核心)
def make_sound(animal: Animal):
    animal.speak()

# 测试多态
if __name__ == '__main__':
    dog = Dog()
    cat = Cat()
    sheep = Sheep()

    # 同一个方法,不同实现
    make_sound(dog)    # 输出:汪汪汪
    make_sound(cat)    # 输出:喵喵喵
    make_sound(sheep)  # 输出:咩咩咩

4.3.4 多态的优点

  1. 代码解耦:不依赖具体子类,只依赖父类接口,降低代码耦合度

  2. 易于扩展:新增子类时,无需修改原有代码,直接重写方法即可

  3. 通用性强:统一调用方式,适配所有继承父类的子类对象

4.3.5 多态的适用场景

  • 统一接口设计(如:不同支付方式、不同文件读取、不同动物行为)

  • 框架 / 工具类开发(屏蔽底层实现,对外提供统一调用方式)

  • 大型项目模块化开发(降低模块间依赖)

4.4 面向对象三大特性总结

特性 核心作用 关键字 / 语法 核心价值
封装 保护数据、隐藏实现 __私有属性、公开方法 数据安全、代码规范
继承 代码复用、功能扩展 class 子类(父类)super() 减少冗余、逻辑清晰
多态 统一接口、多种实现 继承 + 方法重写 灵活扩展、通用调用

五、属性与方法

5.1 静态属性与静态方法

静态属性和静态方法本质是"封装在类内部的全局变量和函数",用于实现逻辑隔离,方便代码维护与复用,与具体对象无关。

5.1.1 问题引入:代码整理需求

某服务器维护脚本包含大量分散的函数和变量,难以分类管理和查找(如磁盘处理、网络处理、内存处理函数混合),需通过面向对象语法实现逻辑隔离。

5.1.2 核心语法

复制代码
class 类名:
    """包含静态属性和静态方法的类"""
    # 静态属性:声明在类内部、方法外部的变量
    静态属性名 = 属性值
    
    # 静态方法:@staticmethod 装饰,无 self/cls 参数
    @staticmethod
    def 静态方法名(形参...):
        """静态方法:独立功能函数"""
        代码逻辑

5.1.3 示例:服务器维护脚本(逻辑隔离版)

复制代码
"""
服务器维护脚本:通过静态属性/方法实现功能逻辑隔离
"""
class Disk:
    """磁盘处理类"""
    DISK_MAX_USAGE = 0.8
    @staticmethod
    def disk_io():
        print("执行磁盘读写维护...")
    @staticmethod
    def disk_clean():
        print("执行磁盘清理...")

class Net:
    """网络处理类"""
    NET_PERCENT = 0.6
    @staticmethod
    def net_io():
        print("执行网络吞吐量监测...")

class Memory:
    """内存处理类"""
    MEMORY_MAX_W = 0.9
    @staticmethod
    def memory_warning():
        print(f"内存告警阈值:{Memory.MEMORY_MAX_W}")

class Cpu:
    """CPU处理类"""
    @staticmethod
    def cpu_usage():
        print("执行CPU监测...")

5.1.4 调用方式

  • 访问静态属性:类名.静态属性名

  • 调用静态方法:类名.静态方法名()

  • 无需创建对象,不推荐用对象调用

    if name == 'main':
    print(Disk.DISK_MAX_USAGE)
    Disk.disk_io()
    Net.net_io()
    Memory.memory_warning()
    Cpu.cpu_usage()

5.1.5 示例:文章操作类

复制代码
class Article:
    max_words = 2000
    @staticmethod
    def publisher(title, content, publish_time, author):
        print(f"===== 发表文章 =====")
        print(f"标题:{title}")
    @staticmethod
    def modify(title, new_content):
        print(f"===== 修改文章 =====")
    @staticmethod
    def delete(title):
        print(f"===== 删除文章 =====")

# 使用
print(Article.max_words)
Article.publisher("Python 3.13发布","内容","2024-11-28","gf")

5.1.6 核心说明

  • 本质:静态属性 = 类内全局变量,静态方法 = 类内工具函数
  • 共享性:所有对象共享,修改后全局生效
  • 适用场景:脚本开发、简单工具函数、功能逻辑分组

5.2 类属性与类方法

类属性和类方法是类的 **"公共资源"**,被所有对象共享,用于统一配置、共享数据。

5.2.1 问题引入:共享属性需求

开发文章类,要求:

  • 所有文章最大字数相同

  • 所有文章出版社信息统一

  • 提供统一方法获取共享信息

5.2.2 核心语法

复制代码
class 类名:
    # 类属性:全大写命名
    类属性名 = 属性值
    
    @classmethod
    def 类方法名(cls, 形参...):
        """cls 代表当前类"""
        print(cls.类属性名)

5.2.3 示例:文章类(类属性 / 类方法)

复制代码
class Article:
    MAX_WORDS = 2000
    PUBLISH_HOUSE = "XXX出版"
    
    def __init__(self, title, content, author):
        self.title = title
        self.content = content
        self.author = author
    
    @classmethod
    def get_publish_info(cls):
        print(f"出版社:{cls.PUBLISH_HOUSE}")

5.2.4 示例:课程类

复制代码
class PythonAI:
    COURSE_NAME = "Python AI 综合应用设计"
    def __init__(self, student_cnt, teacher, cycle):
        self.student_cnt = student_cnt
        self.teacher = teacher
        self.cycle = cycle
    
    @classmethod
    def introduce(cls):
        print(f"课程名称:{cls.COURSE_NAME}")
    
    def get_class_info(self):
        print(f"讲师:{self.teacher},人数:{self.student_cnt}")

5.2.5 使用方式

复制代码
# 类名直接访问(推荐)
print(PythonAI.COURSE_NAME)
PythonAI.introduce()

# 对象也可访问(不推荐)
stu = PythonAI(90,"大牧",50)
print(stu.COURSE_NAME)

5.2.6 适用场景

  • 类属性:共享常量、配置阈值、全局参数

  • 类方法:操作类属性、统一业务逻辑

  • 优势:修改一处,全部对象同步更新

5.3 成员属性与成员方法

成员属性 / 方法是对象独有的资源,每个对象数据独立,互不干扰,是面向对象最核心用法。

5.3.1 核心概念

  • 成员属性:对象自己的变量(姓名、年龄、账号)

  • 成员方法:对象自己的行为(登录、学习、展示信息)

  • 依赖 self,必须通过对象调用

5.3.2 核心语法

复制代码
class 类名:
    def __init__(self, 形参1, 形参2):
        self.成员属性1 = 形参1
        self.成员属性2 = 形参2
    
    def 成员方法(self):
        print(self.成员属性1)

5.3.3 示例:人类

复制代码
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def study(self, way):
        print(f"{self.name}({self.age}):{way}")

5.3.4 示例:用户对象操作

复制代码
class User:
    def __init__(self, username, password):
        self.username = username
        self.password = password
    def login(self):
        return self.username == "admin" and self.password == "123"

# 使用
user = User("admin","123")
print(user.username)
user.password = "111"
print(user.login())

5.3.5 核心特点

  • 独立性:每个对象数据隔离

  • 依赖性:必须通过对象访问,类无法直接调用

  • 适用场景:业务系统、多实例对象、个性化数据

5.4 三种属性 / 方法对比

5.4.1 属性对比表

类型 定义位置 访问方式 共享性 影响范围
静态属性 类内、方法外 类名 / 对象 全局共享 全部生效
类属性 类内、方法外 类名 / 对象 类内共享 全部对象
成员属性 __init__ 仅对象 对象独立 仅当前对象

5.4.2 方法对比表

方法类型 装饰器 默认参数 可访问数据
成员方法 self 成员属性 + 类属性
类方法 @classmethod cls 类属性
静态方法 @staticmethod 无(工具函数)

5.4.3 快速选择指南

  • 对象独有数据 → 成员属性

  • 全类共享数据 → 类属性

  • 工具函数、分组功能 → 静态方法

  • 操作共享配置 → 类方法

  • 对象自身行为 → 成员方法

5.5 实战案例:图书管理系统

复制代码
class Book:
    def __init__(self, book_id, title, author, stock):
        self.book_id = book_id
        self.title = title
        self.author = author
        self.stock = stock
        self.borrowed = 0
    
    def borrow(self):
        if self.stock > self.borrowed:
            self.borrowed +=1
            return "借阅成功"
        return "库存不足"

class Library:
    def __init__(self):
        self.books = []
    
    def add_book(self, book):
        self.books.append(book)
    
    def find_book(self, book_id):
        for b in self.books:
            if b.book_id == book_id:
                return b
        return None

5.6 综合案例:用户认证系统

5.6.1 需求

  • 普通用户 / 管理员

  • 登录、查看信息

  • 管理员可增删用户

  • 密码加密存储

5.6.2 代码实现

复制代码
import hashlib
class User:
    def __init__(self, username, password):
        self.username = username
        self.password = self._encrypt(password)
    
    @staticmethod
    def _encrypt(pwd):
        md5 = hashlib.md5()
        md5.update(pwd.encode())
        return md5.hexdigest()
    
    def login(self, user, pwd):
        return self.username == user and self.password == self._encrypt(pwd)
    
    def show_info(self):
        print(f"用户:{self.username},角色:普通用户")

class Admin(User):
    def __init__(self, username, password):
        super().__init__(username, password)
        self.user_list = []
    
    def create_user(self, username, password):
        self.user_list.append(User(username, password))
    
    def delete_user(self, username):
        for u in self.user_list:
            if u.username == username:
                self.user_list.remove(u)

5.6.3 测试

复制代码
admin = Admin("admin","admin123")
admin.create_user("user1","123456")
admin.show_info()
相关推荐
A懿轩A2 小时前
【2026 最新】Python 下载与安装:在 macOS 下使用 Homebrew 和 pyenv 完美管理多版本 Python
python·macos·mac
浮芷.2 小时前
Flutter 框架跨平台鸿蒙开发 - 急救指南应用
学习·flutter·华为·harmonyos·鸿蒙
Freak嵌入式2 小时前
小作坊 GitHub 协作闭环:fork-sync-dev-pr-merge 实战指南
python·github·远程工作·代码规范·micropython·协作
跟着珅聪学java2 小时前
在 Java 中处理 JSON 去除空 children数组,可以使用 Jackson 库。这里有几种实现方式
开发语言·windows·python
嵌入式×边缘AI:打怪升级日志2 小时前
Linux 常用命令学习笔记(续):查找、压缩、vi 编辑器与其他命令
linux·笔记·学习
Chase_______2 小时前
【Python基础 | 第5章】面向对象与异常处理:一文搞懂类、对象、封装、继承、多态
开发语言·python
AI成长日志2 小时前
【笔面试算法学习专栏】链表操作·基础三题精讲(206.反转链表、141.环形链表、21.合并两个有序链表)
学习·算法·面试
YanDDDeat2 小时前
【大模型微调】基于 Llama3-8B 的 LoRA 微调专有领域QA 问答对生成模型
python·语言模型·llama
小李云雾2 小时前
Python Web 路由详解:核心知识点全覆盖
开发语言·前端·python·路由