当前位置: 首页 > news >正文

Python 装饰器使用详解

文章目录

    • 0. 引言
    • 1. 什么是装饰器?
    • 2. 装饰器的基本语法
    • 3. 装饰器的工作原理
    • 4. 常见装饰器应用场景
      • 4.1. 日志记录
      • 4.2. 权限校验
      • 4.3. 缓存
    • 5. 多重装饰器的执行顺序
    • 6. 装饰器的高级用法
      • 6.1. 带参数的装饰器
      • 6.2. 使用 `functools.wraps`
      • 6.3. 类装饰器
    • 7. 图示说明
      • 7.1. 单一装饰器的执行流程
      • 2. 多重装饰器的执行流程
      • 3. 带参数装饰器的执行流程
    • 总结
    • 8 参考资料

0. 引言

Python装饰器(Decorator) 不仅可以让你的代码更加简洁、可读,还能有效地实现功能的复用和扩展。本文将带你深入了解Python装饰器的概念、原理及其应用。

1. 什么是装饰器?

装饰器是一种高阶函数,它接受一个函数作为参数,并返回一个新的函数。通过装饰器,我们可以在不修改原函数代码的前提下,动态地为其添加额外的功能。
简单来说,装饰器就是函数的包装器,它可以在函数执行前后添加一些操作。

2. 装饰器的基本语法

在Python中,装饰器通常使用 @ 符号来应用于函数或类。下面是一个简单的装饰器示例:

def my_decorator(func):def wrapper():print("函数执行前的操作")func()print("函数执行后的操作")return wrapper@my_decorator
def say_hello():print("Hello!")say_hello()

输出:

函数执行前的操作
Hello!
函数执行后的操作

在这个例子中:

  • my_decorator 是一个装饰器,它接受一个函数 func 作为参数。
  • wrapper 是一个内部函数,它在调用 func 前后添加了额外的打印操作。
  • @my_decoratorsay_hello 函数传递给装饰器,并将返回的 wrapper 函数重新赋值给 say_hello

因此,当我们调用 say_hello() 时,实际执行的是 wrapper() 函数。

3. 装饰器的工作原理

装饰器的核心在于闭包高阶函数。让我们通过一个更详细的示例来理解装饰器的工作机制。

def decorator(func):print("装饰器被调用")def wrapper(*args, **kwargs):print("在函数执行前")result = func(*args, **kwargs)print("在函数执行后")return resultreturn wrapper@decorator
def add(a, b):print(f"执行加法: {a} + {b}")return a + bresult = add(3, 5)
print(f"结果是: {result}")

输出:

装饰器被调用
在函数执行前
执行加法: 3 + 5
在函数执行后
结果是: 8

工作流程图示:

+------------------+
| @decorator        |
| 装饰器被调用        |
| add 函数被传入      |
+---------+--------+|v
+---------+--------+
| 返回 wrapper 函数 |
+---------+--------+|v
+---------+--------+
| 调用 add(3, 5)   | ---> 实际上调用的是 wrapper(3, 5)
+---------+--------+|v
+---------+--------+
| 打印 "在函数执行前"|
| 调用原始 add    |
| 打印 "执行加法:3 +5"|
| 打印 "在函数执行后"|
+---------+--------+|v
+---------+--------+
| 返回结果 8        |
+------------------+

解释:

  • 当Python解释器遇到 @decorator 时,它会先调用 decorator(add)
  • decorator 函数在执行时首先打印“装饰器被调用”。
  • decorator 返回了 wrapper 函数,因此 add 函数被替换为 wrapper
  • 当调用 add(3, 5) 时,实际上调用的是 wrapper(3, 5),它在执行 func(3, 5)(即原始的 add 函数)前后添加了打印操作。

4. 常见装饰器应用场景

装饰器在实际开发中有着广泛的应用,以下是几个常见的使用场景:

4.1. 日志记录

记录函数的调用信息、参数、返回值等,有助于调试和监控。

def log_decorator(func):def wrapper(*args, **kwargs):print(f"调用函数 {func.__name__},参数: {args}, {kwargs}")result = func(*args, **kwargs)print(f"函数 {func.__name__} 返回: {result}")return resultreturn wrapper@log_decorator
def multiply(a, b):return a * bmultiply(4, 5)

输出:

调用函数 multiply,参数: (4, 5), {}
函数 multiply 返回: 20

4.2. 权限校验

在函数执行前进行权限检查,确保用户有权限执行该操作。

def requires_permission(permission):def decorator(func):def wrapper(*args, **kwargs):if not user_has_permission(permission):raise PermissionError("没有权限执行此操作")return func(*args, **kwargs)return wrapperreturn decorator@requires_permission('admin')
def delete_user(user_id):print(f"删除用户 {user_id}")

4.3. 缓存

缓存函数的计算结果,避免重复计算,提高性能。

def cache_decorator(func):cache = {}def wrapper(*args):if args in cache:print("使用缓存")return cache[args]result = func(*args)cache[args] = resultreturn resultreturn wrapper@cache_decorator
def fibonacci(n):if n <= 1:return nreturn fibonacci(n-1) + fibonacci(n-2)print(fibonacci(5))

5. 多重装饰器的执行顺序

当一个函数被多个装饰器装饰时,装饰器的执行顺序可能会让人感到困惑。下面通过一个示例来说明多重装饰器的执行顺序。

def decorator_a(func):print("装饰器 A 被调用")def wrapper(*args, **kwargs):print("装饰器 A 在函数执行前")result = func(*args, **kwargs)print("装饰器 A 在函数执行后")return resultreturn wrapperdef decorator_b(func):print("装饰器 B 被调用")def wrapper(*args, **kwargs):print("装饰器 B 在函数执行前")result = func(*args, **kwargs)print("装饰器 B 在函数执行后")return resultreturn wrapper@decorator_a
@decorator_b
def greet(name):print(f"Hello, {name}!")greet("Alice")

输出:

装饰器 A 被调用
装饰器 B 被调用
装饰器 A 在函数执行前
装饰器 B 在函数执行前
Hello, Alice!
装饰器 B 在函数执行后
装饰器 A 在函数执行后

执行顺序图示:

装饰器应用阶段:
+-----------------+       +-----------------+
| decorator_a     |       | decorator_b     |
| 调用 decorator_a |       | 调用 decorator_b |
+--------+--------+       +--------+--------+|                         |v                         v
+--------+--------+       +--------+--------+
| 返回 wrapper_a   |       | 返回 wrapper_b   |
+--------+--------+       +--------+--------+|                         |+----------> greet <-------+指向 wrapper_a函数调用阶段:
+-----------------+
| 调用 greet("Alice") |
+--------+--------+|v
+--------+--------+
| wrapper_a       |
| 打印 "装饰器 A 在函数执行前" |
| 调用 wrapper_b  |
+--------+--------+|v
+--------+--------+
| wrapper_b       |
| 打印 "装饰器 B 在函数执行前" |
| 调用 greet ("Hello, Alice!") |
| 打印 "装饰器 B 在函数执行后" |
+--------+--------+|v
+--------+--------+
| wrapper_a       |
| 打印 "装饰器 A 在函数执行后" |
+-----------------+

解释:

  • 装饰器的应用顺序是自下而上

    • 首先,greet 函数被 decorator_b 装饰,生成 wrapper_b
    • 然后,wrapper_bdecorator_a 装饰,生成 wrapper_a
    • 最终,greet 指向 wrapper_a
  • 函数调用的执行顺序是自上而下

    • 调用 greet("Alice") 实际上调用的是 wrapper_a("Alice")
    • wrapper_a 打印“装饰器 A 在函数执行前”,然后调用 wrapper_b("Alice")
    • wrapper_b 打印“装饰器 B 在函数执行前”,然后调用原始的 greet("Alice")
    • 原始的 greet 打印“Hello, Alice!”。
    • 然后,wrapper_b 打印“装饰器 B 在函数执行后”。
    • 最后,wrapper_a 打印“装饰器 A 在函数执行后”。

6. 装饰器的高级用法

6.1. 带参数的装饰器

有时候,装饰器本身需要接受参数,这时需要使用三层嵌套函数

def repeat(num_times):def decorator(func):def wrapper(*args, **kwargs):for _ in range(num_times):result = func(*args, **kwargs)return resultreturn wrapperreturn decorator@repeat(num_times=3)
def say(message):print(message)say("Hello!")

输出:

Hello!
Hello!
Hello!

6.2. 使用 functools.wraps

在装饰器中,使用 functools.wraps 可以保留原函数的元数据,如函数名、文档字符串等。

import functoolsdef my_decorator(func):@functools.wraps(func)def wrapper(*args, **kwargs):print("调用前")return func(*args, **kwargs)return wrapper@my_decorator
def example():"""这是一个示例函数"""print("示例函数执行")print(example.__name__)  # 输出: example
print(example.__doc__)   # 输出: 这是一个示例函数

6.3. 类装饰器

装饰器不仅可以用于函数,也可以用于类。

def class_decorator(cls):class WrappedClass:def __init__(self, *args, **kwargs):self.wrapped_instance = cls(*args, **kwargs)def __getattr__(self, attr):return getattr(self.wrapped_instance, attr)def new_method(self):print("这是新添加的方法")return WrappedClass@class_decorator
class MyClass:def method(self):print("原始方法")obj = MyClass()
obj.method()
obj.new_method()

输出:

原始方法
这是新添加的方法

7. 图示说明

为了更直观地理解装饰器的工作原理及其执行顺序,下面通过几张示意图来辅助说明。

7.1. 单一装饰器的执行流程

示意图:

装饰器应用阶段:
+-----------------+
| Original Func   |  (被装饰的函数)
+--------+--------+|v
+--------+--------+
| Decorator       |  (装饰器函数)
| 返回 Wrapper    |
+--------+--------+|v
+--------+--------+
| Wrapper Func    |  (包装后的函数)
+--------+--------+函数调用阶段:
+-----------------+
| 调用 Wrapper    |
+--------+--------+|v
+--------+--------+
| 执行装饰器前操作 |
+--------+--------+|v
+--------+--------+
| 执行原始函数    |
+--------+--------+|v
+--------+--------+
| 执行装饰器后操作 |
+-----------------+

解释:

  1. 装饰器应用阶段:原始函数通过装饰器包装,生成一个新的包装函数。
  2. 函数调用阶段:调用包装函数时,先执行装饰器前的操作,再执行原始函数,最后执行装饰器后的操作。

2. 多重装饰器的执行流程

示意图:

装饰器应用阶段:
+-----------------+       +-----------------+
| Original Func   |       | Decorator B     |
+--------+--------+       +--------+--------+|                         |v                         v
+--------+--------+       +--------+--------+
| Decorator A     |       | 返回 Wrapper B   |
| 返回 Wrapper A  |       +-----------------+
+--------+--------+|v
+--------+--------+
| Wrapper A       |
+-----------------+函数调用阶段:
+-----------------+
| 调用 Wrapper A  |
+--------+--------+|v
+--------+--------+
| 执行 Decorator A 前操作 |
+--------+--------+|v
+--------+--------+
| 调用 Wrapper B  |
+--------+--------+|v
+--------+--------+
| 执行 Decorator B 前操作 |
+--------+--------+|v
+--------+--------+
| 执行原始函数    |
+--------+--------+|v
+--------+--------+
| 执行 Decorator B 后操作 |
+--------+--------+|v
+--------+--------+
| 执行 Decorator A 后操作 |
+-----------------+

解释:

  1. 装饰器应用阶段

    • 原始函数首先被 Decorator B 装饰,生成 Wrapper B
    • 然后,Wrapper BDecorator A 装饰,生成 Wrapper A
    • 最终,函数指向 Wrapper A
  2. 函数调用阶段

    • 调用 Wrapper A,执行 Decorator A 的前置操作。
    • Wrapper A 调用 Wrapper B,执行 Decorator B 的前置操作。
    • Wrapper B 调用原始函数。
    • 执行 Decorator B 的后置操作。
    • 执行 Decorator A 的后置操作。

3. 带参数装饰器的执行流程

示意图:

装饰器应用阶段:
+-----------------+
| repeat(num_times=3) |
+--------+--------+|v
+--------+--------+
| Decorator       |
| 返回 Wrapper     |
+--------+--------+|v
+--------+--------+
| 原始函数         |
+--------+--------+函数调用阶段:
+-----------------+
| 调用 Wrapper    |
+--------+--------+|v
+--------+--------+
| 重复调用原始函数 |
| 3 次            |
+-----------------+

解释:

  1. 装饰器应用阶段:带参数的装饰器 repeat 接受参数 num_times=3,返回装饰器函数 decorator,然后 decorator 返回 wrapper 函数。
  2. 函数调用阶段:调用 wrapper 时,根据 num_times 的值,重复调用原始函数 3 次。

总结

装饰器通过函数包装器的方式,允许开发者在不修改原函数代码的前提下,为其添加额外的功能。

8 参考资料

  • Python 官方文档 - 装饰器
  • Python Decorators 101
  • Functools 模块

相关文章:

Python 装饰器使用详解

文章目录 0. 引言1. 什么是装饰器&#xff1f;2. 装饰器的基本语法3. 装饰器的工作原理4. 常见装饰器应用场景4.1. 日志记录4.2. 权限校验4.3. 缓存 5. 多重装饰器的执行顺序6. 装饰器的高级用法6.1. 带参数的装饰器6.2. 使用 functools.wraps6.3. 类装饰器 7. 图示说明7.1. 单…...

Vue使用qrcodejs2-fix生成网页二维码

安装qrcodejs2-fix npm install qrcodejs2-fix核心代码 在指定父view中生成一个二维码通过id找到父布局 //通过id找到父布局let codeView document.getElementById("qrcode")new QRCode(codeView, {text: "测试",width: 128,height: 128,colorDark: #00…...

兼容多个AI应用接口,支持用户自定义切换AI接口

项目背景 2023年ChatGPT横空出世&#xff0c;给IT行业造成了巨大的反响。我第一次发现这个ChatGPT有着如此神奇的功能&#xff08;智能对话&#xff0c;知识问答&#xff0c;代码生成&#xff0c;逻辑推理等&#xff09;&#xff0c;我感到非常吃惊&#xff01;经过一番学习和…...

[docker]入门

本文章主要讲述的是&#xff0c;docker基本实现原理&#xff0c;docker概念的解释&#xff0c;docker的使用场景以及docker打包与部署的应用。 文章中docker所运行的系统&#xff1a;CentOS Linux release 7.9.2009 (Core) 目录 docker是什么&#xff0c;什么时候需要去使用 …...

《让手机秒变超级电脑!ToDesk云电脑、易腾云、青椒云移动端评测》

前言 科技发展到如今2024年&#xff0c;可以说每一年都在发生翻天覆地的变化。而云上这个词时常都被大家提起&#xff0c;从个人设备连接到云端在如今在也不是梦了。而云电脑这个市场近年来迅速发展&#xff0c;无需购买和维护额外的硬件就可以体验到电脑端顶配的性能和体验&am…...

Nginx处理带有分号“;“的路径

一、背景 安全渗透测试发现springboot 未授权访问的actuator和Swagger-ui 信息泄露的漏洞&#xff0c;需要规避。解决方案中较简单的就是通过Nginx将相关的接口转发到403页面。 在配置的过程当中&#xff0c;遇到了带有…;的路径&#xff1a;http://{ip:port}/{path}/…;/actu…...

Spring Boot框架下的心理教育辅导系统开发

1绪 论 1.1研究背景 随着计算机和网络技术的不断发展&#xff0c;计算机网络已经逐渐深入人们的生活&#xff0c;网络已经能够覆盖我们生活的每一个角落&#xff0c;给用户的网上交流和学习提供了巨大的方便。 当今社会处在一个高速发展的信息时代&#xff0c;计算机网络的发展…...

PyTorch 图像分割模型教程

PyTorch 图像分割模型教程 在图像分割任务中&#xff0c;目标是将图像的每个像素归类为某一类&#xff0c;以分割出特定的物体。PyTorch 提供了非常灵活的工具&#xff0c;可以用于构建和训练图像分割模型。我们将使用 PyTorch 的经典网络架构&#xff0c;如 UNet 和 DeepLabV…...

物联网——USART协议

接口 串口通信 硬件电路 电平标准 串口参数、时序 USART USART主要框图 TXE: 判断发送寄存器是否为空 RXNE: 判断接收寄存器是否非空 RTS为输出信号&#xff0c;用于表示MCU串口是否准备好接收数据&#xff0c;若输出信号为低电平&#xff0c;则说明MCU串口可以接收数据&#…...

前端框架对比与选择:如何在现代Web开发中做出最佳决策

随着互联网技术的迅速发展&#xff0c;前端开发在现代Web应用开发中扮演了至关重要的角色。对于开发者来说&#xff0c;选择合适的前端框架不仅能够提高开发效率&#xff0c;还能确保项目的可维护性和可扩展性。目前市面上有多种主流的前端框架和库&#xff0c;每一种都有其独特…...

【浅水模型MATLAB】尝试复刻SCI论文中的溃坝流算例

【浅水模型MATLAB】尝试复刻SCI论文中的溃坝流算例 前言问题描述控制方程及数值方法浅水方程及其数值计算方法边界条件的实现 代码框架与关键代码模拟结果 更新于2024年9月17日 前言 这篇博客算是学习浅水方程&#xff0c;并利用MATLAB复刻Liang (2004)1中溃坝流算例的一个记录…...

探索云计算:IT行业的未来趋势

探索云计算&#xff1a;IT行业的未来趋势 在当今快速发展的科技世界&#xff0c;云计算已成为IT行业的核心趋势之一。无论是大企业还是初创公司&#xff0c;越来越多的组织正在转向云计算&#xff0c;以实现更高效的运营和更快的创新。在这篇博文中&#xff0c;我们将探讨云计算…...

[PICO VR眼镜]眼动追踪串流Unity开发与使用方法,眼动追踪打包报错问题解决(Eye Tracking/手势跟踪)

前言 最近在做一个工作需要用到PICO4 Enterprise VR头盔里的眼动追踪功能&#xff0c;但是遇到了如下问题&#xff1a; 在Unity里面没法串流调试眼动追踪功能&#xff0c;根本获取不到Device&#xff0c;只能将整个场景build成APK&#xff0c;安装到头盔里&#xff0c;才能在…...

一周热门|比GPT-4强100倍,OpenAI有望年底发布GPT-Next;1个GPU,1分钟,16K图像

大模型周报将从【企业动态】【技术前瞻】【政策法规】【专家观点】四部分&#xff0c;带你快速跟进大模型行业热门动态。 01 企业动态 Ilya 新公司 SSI 官宣融资 10 亿美元 据路透社报道&#xff0c;由 OpenAI 联合创始人、前首席科学家 Ilya Sutskever 在 2 个多月前共同创…...

软考流水线计算

某计算机系统输入/输出采用双缓冲工作方式&#xff0c;其工作过程如下图所示&#xff0c;假设磁盘块与缓冲区大小相同&#xff0c;每个盘块读入缓冲区的时间T为10μs&#xff0c;由缓冲区送至用户区的时间M为6μs&#xff0c;系统对每个磁盘块数据的处理时间C为2μs。若用户需要…...

1份可以派上用场丢失数据恢复的应用程序列表

无论如何&#xff0c;丢失您的宝贵数据是可怕的。您的 Android 或 iOS 设备可能由于事故、硬件损坏、存储卡问题等而丢失了数据。这就是为什么我们编制了一份可以派上用场以恢复丢失数据的应用程序列表。 如果您四处走动&#xff0c;您大多会随身携带手机或其他移动设备。这些…...

MySQL Workbench 超详细安装教程(一步一图解,保姆级安装)

前言&#xff1a; MySQL Workbench 是一款强大的数据库设计和管理工具&#xff0c;它提供了图形化界面&#xff0c;使得数据库的设计、管理、查询等操作变得更加直观和便捷。本文将详细介绍如何在 Windows 系统上安装 MySQL Workbench。相信读者看这篇文章前一定安装了MySQL数…...

深度学习常见面试题及答案(16~20)

算法学习、4对1辅导、论文辅导或核心期刊以及其他学习资源可以通过公众号滴滴我 文章目录 16. 简述深度学习中的批量归一化&#xff08;Batch Normalization&#xff09;的目的和工作原理。一、批量归一化的目的1. 加速训练收敛&#xff1a;2. 提高模型泛化能力&#xff1a;3. …...

Packet Tracer - IPv4 ACL 的实施挑战(完美解析)

目标 在路由器上配置命名的标准ACL。 在路由器上配置命名的扩展ACL。 在路由器上配置扩展ACL来满足特定的 通信需求。 配置ACL来控制对网络设备终端线路的 访问。 在适当的路由器接口上&#xff0c;在适当的方向上 配置ACL。…...

Langchain-chatchat源码部署及测试实验

一年多前接触到Langchain-chatchat的0.2版本,对0.2版本进行了本地部署和大量更新,但0.2版本对最新的大模型支持不够好,部署框架支持也不好且不太稳定,特别是多模态大模型,因此本次主要介绍0.3版本的源码部署,希望对大家有所帮助。Langchain-chatchat从0.3版本开始,支持更…...

OpenCore Legacy Patcher终极指南:让老旧Mac焕发新生的完整方案

OpenCore Legacy Patcher终极指南&#xff1a;让老旧Mac焕发新生的完整方案 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher OpenCore Legacy Patcher&#xf…...

Phi-3-mini-4k-instruct-gguf代码实例:Python requests调用Web API完整示例

Phi-3-mini-4k-instruct-gguf代码实例&#xff1a;Python requests调用Web API完整示例 1. 模型简介 Phi-3-mini-4k-instruct-gguf是微软Phi-3系列中的轻量级文本生成模型GGUF版本&#xff0c;特别适合问答、文本改写、摘要整理和简短创作等场景。这个经过优化的版本可以直接…...

Qwen3-TTS WebUI使用技巧:长文本自动分段+情感一致性保持方法

Qwen3-TTS WebUI使用技巧&#xff1a;长文本自动分段情感一致性保持方法 Qwen3-TTS-12Hz-1.7B-CustomVoice 是一款强大的语音合成模型&#xff0c;支持10种主要语言和多种方言语音风格&#xff0c;具备出色的上下文理解能力和情感表达能力。但在处理长文本时&#xff0c;如何保…...

用ZYNQ PS-SPI给Flash测个速:华邦W25Q80在25MHz时钟下的真实读写性能报告

ZYNQ PS-SPI Flash性能深度评测&#xff1a;华邦W25Q80在25MHz时钟下的极限挖掘 当我们需要在嵌入式系统中选择一款Flash存储器时&#xff0c;数据手册上的理论参数往往无法反映真实应用场景下的性能表现。本文将基于Xilinx ZYNQ平台的PS-SPI接口&#xff0c;对华邦W25Q80 Flas…...

利用快马AI一键生成vmware虚拟机下载与配置脚本,快速搭建开发原型环境

今天想和大家分享一个快速搭建开发环境的实用技巧——利用AI工具自动生成VMware虚拟机下载与配置脚本。作为一个经常需要测试不同开发环境的程序员&#xff0c;我发现手动配置虚拟机实在太费时间了&#xff0c;直到尝试了InsCode(快马)平台的AI生成功能&#xff0c;整个过程变得…...

LongCat-Video:136亿参数开源AI视频生成模型的技术突破与实践指南

LongCat-Video&#xff1a;136亿参数开源AI视频生成模型的技术突破与实践指南 【免费下载链接】LongCat-Video 项目地址: https://ai.gitcode.com/hf_mirrors/meituan-longcat/LongCat-Video 在人工智能视频生成领域&#xff0c;长视频生成一直是技术挑战的制高点。传统…...

高效代码分析利器:cloc工具全场景使用指南

1. 为什么你需要cloc这个代码统计神器 第一次接手一个遗留项目时&#xff0c;我盯着密密麻麻的目录树发愁&#xff1a;这堆代码到底有多少实际内容&#xff1f;注释占比多少&#xff1f;不同语言的文件各有多少&#xff1f;直到同事推荐了cloc工具&#xff0c;输入一行命令就得…...

ISO/SAE 21434:2021 逐条审核判定表

A 章节号&#xff5c;B 条款&#xff5c;C 要求内容&#xff5c;D 符合性&#xff5c;E 证据 / 说明&#xff5c;F&#xff1a;不符合整改项符合性选项&#xff1a;符合 / 部分符合 / 不符合 / 不适用章节号条款审核要求内容符合性证据 / 备注整改项44.1建立网络安全生命周…...

如何突破教育资源壁垒?智能解析工具让电子课本获取效率提升200%

如何突破教育资源壁垒&#xff1f;智能解析工具让电子课本获取效率提升200% 【免费下载链接】tchMaterial-parser 国家中小学智慧教育平台 电子课本下载工具&#xff0c;帮助您从智慧教育平台中获取电子课本的 PDF 文件网址并进行下载&#xff0c;让您更方便地获取课本内容。 …...

palworld-host-save-fix全攻略:解决幻兽帕鲁存档迁移难题的实战指南

palworld-host-save-fix全攻略&#xff1a;解决幻兽帕鲁存档迁移难题的实战指南 【免费下载链接】palworld-host-save-fix 项目地址: https://gitcode.com/gh_mirrors/pa/palworld-host-save-fix 在幻兽帕鲁的冒险旅程中&#xff0c;更换服务器或迁移平台时的存档丢失问…...