跳到主要内容 Python 装饰器详解:概念、类型与应用场景 | 极客日志
Python 算法
Python 装饰器详解:概念、类型与应用场景 Python 装饰器的基本概念、函数与类装饰器类型,以及内置装饰器(@property, @classmethod, @staticmethod)。通过日志记录、速度计时、权限检查等实际应用场景,展示了如何利用装饰器在不修改原代码的情况下扩展功能,提升代码复用性与可维护性。
刀狂 发布于 2026/3/24 更新于 2026/4/16 3 浏览Python 装饰器详解
一、基本概念
装饰器本质上是一个接受 函数 作为 参数 并返回一个 新函数 的函数。装饰器允许在不修改原函数代码的情况下,为函数添加额外的功能。
下面通过一个例子来解释这个概念。
装饰器顾名思义就是一个具有装饰作用的东西(在 Python 中装饰器对应的就是一个函数)。
'装饰器允许在不修改原函数代码的情况下,为函数添加额外的功能。'这句话可以这么理解:比如现在你有一个杯子(礼物)想要送人,光送杯子太难看,所以肯定想要装饰一下,这个时候可以找一个礼物盒(装饰器)把杯子装进去,这个礼物盒对于杯子而言只是起到一个装饰的作用,它不会改变杯子的功能(盛水)。
在 Python 中,我们可以使用 A 函数对 B 函数添加一些功能,但是又可以做到不修改 B 函数的代码,这个时候 A 函数对 B 函数而言就是一个装饰器。
示例:先看一个普通函数
def say_hello ():
print ("你好!" )
say_hello()
假如我们想在说'你好'之前和之后都加上一些装饰性的语句,可以这样做:
def decorator (func ):
def wrapper ():
print ("准备开始啦!" )
func()
print ("结束啦!" )
return wrapper
def say_hello ():
print ("你好!" )
decorated_say_hello = decorator(say_hello)
decorated_say_hello()
通过上面的例子便可以理解这句话:'装饰器本质上是一个接受 函数 作为 参数 并返回一个 新函数 的函数。'上面例子中 decorator 函数的参数是另一个函数(func),并且 decorator 函数最终返回了一个函数 wrapper,这便是'接受函数作为参数并返回一个新函数'这句话的体现。
另外,很多人对于装饰器是两个函数嵌套的这种形式可能不太理解,个人理解如下:
在上面例子中,decorator 这个单词翻译过来是装饰的意思,wrapper 翻译过来是包装的意思。比如现在有一个苹果,我们想要给它裹上一层包装变成平安果,这个包装的东西可以是纸质的也可以是塑料的,但不管是什么材质,当给苹果裹上包装之后,我们就可以说对这个苹果进行了装饰,当包装纸包裹了苹果之后,我们才可以把它成为装饰器。换句话说就是使用一个装饰器包装纸装饰苹果。这三者之间的逻辑关系如下:
Python 提供了更简单的写法,就是用 @装饰器名字:
def decorator (func ):
def wrapper ():
print ("准备开始啦!" )
func()
print ("结束啦!" )
return wrapper
@decorator
def say_hello ():
print ("你好!" )
say_hello()
二、装饰器的类型
1、函数装饰器
def say_hello_machine (func ):
def wrapper ():
print ("你好!" )
func()
print ("再见!" )
return wrapper
@say_hello_machine
def my_name ():
print ("我是小明" )
my_name()
def say_hello_machine_times (times ):
def real_decorator (func ):
def wrapper ():
for i in range (times):
print ("你好!" )
func()
return wrapper
return real_decorator
@say_hello_machine_times(3 )
def my_name ():
print ("我是小明" )
my_name()
2、类装饰器 除了用函数来做'加工机器',我们还可以用一个'类'(你可以理解为一种蓝图或者零件盒)来组装成一个机器。
class MyDecorator :
def __init__ (self, func ):
self .func = func
def __call__ (self ):
print ("类装饰器说:开始!" )
self .func()
print ("类装饰器说:结束!" )
@MyDecorator
def my_name ():
print ("我是小明" )
my_name()
3、内置装饰器
(1)、@property 它能把一个方法(需要调用的函数)变成属性(直接拿来的值)。
class Circle :
def __init__ (self, radius ):
self .radius = radius
def area (self ):
print (self .radius * self .radius * 3.14 )
circle = Circle(10 )
circle.area()
class Circle :
def __init__ (self, radius ):
self .radius = radius
@property
def area (self ):
print (self .radius * self .radius * 3.14 )
circle = Circle(10 )
circle.area
(2)、@classmethod 它规定这个方法不是属于某个具体对象的,而是属于整个类的。
例如:你有一个'三年级二班'的类。@classmethod 这个方法就像是'统计全班有多少人',这个信息不属于张三或者李四某个具体的学生,而是属于整个班级的。
class ThirdGradeClass :
total_students = 0
def __init__ (self, name ):
self .name = name
ThirdGradeClass.total_students += 1
@classmethod
def get_total_students (cls ):
return cls.total_students
xiaoming = ThirdGradeClass("小明" )
xiaohong = ThirdGradeClass("小红" )
print (ThirdGradeClass.get_total_students())
print (xiaoming.get_total_students())
(3)、@staticmethod 它把一个普通的函数'挂'在了类里面,但这个函数和这个类以及类的具体对象都没有关系。它只是一个放在那里方便你使用的工具。
例如:还是在'三年级二班'的教室里,墙上挂着一个'计算器'。这个计算器不属于任何一个学生,也不属于'班级'这个概念本身,它只是一个放在这里方便大家使用的工具。
class ThirdGradeClass :
@staticmethod
def add_numbers (a, b ):
return a + b
result1 = ThirdGradeClass.add_numbers(5 , 3 )
result2 = xiaoming.add_numbers(10 , 2 )
三、装饰器的应用场景 用一个游戏——《我的世界》(Minecraft)来举个例子。
应用场景 1:【自动日志记录】—— 像游戏里的'成就系统' 你想知道玩家什么时候建造了房子,什么时候挖了矿,并在控制台上记录下来。
笨方法(没有魔法装备):
每次写一个函数,都要在里面手动加一句 print。
def build_house ():
print ("记录:玩家建造了房子!" )
print ("砰!砰!砰!一栋房子盖好了!" )
def mine_ore ():
print ("记录:玩家挖矿了!" )
print ("镐子咣咣咣,挖到了钻石!" )
build_house()
mine_ore()
如果有一百个动作,你要写一百遍 print('记录:玩家...',太累了!而且如果想改记录的内容,要改一百个地方。
聪明方法(穿上'记录'魔法装备):
做一个'记录装饰器',给哪个函数穿上,哪个函数就会自动记录。
def log_action (func ):
def wrapper ():
print (f"记录:玩家进行了 {func.__name__} 操作!" )
func()
return wrapper
@log_action
def build_house ():
print ("砰!砰!砰!一栋房子盖好了!" )
@log_action
def mine_ore ():
print ("镐子咣咣咣,挖到了钻石!" )
build_house()
mine_ore()
记录:玩家进行了 build_house 操作!
砰!砰!砰!一栋房子盖好了!
记录:玩家进行了 mine_ore 操作!
镐子咣咣咣,挖到了钻石!
魔法效果: 代码变得非常干净!你想给哪个功能加记录,就给它'穿'上 @log_action 装备就行。要修改记录格式,只需要改装饰器这一个地方。
应用场景 2:【速度计时】—— 像'速度跑酷'的计时器 你想测试一下玩家完成某个动作(比如砍树、打怪)花了多长时间。
聪明方法(穿上'计时'魔法装备):
做一个'计时装饰器',轻松给任何动作计时。
import time
def timer (func ):
def wrapper ():
start_time = time.time()
func()
end_time = time.time()
print (f"【{func.__name__} 】动作耗时:{end_time - start_time:.2 f} 秒" )
return wrapper
@timer
def chop_tree ():
print ("咔嚓...咔嚓..." )
time.sleep(2 )
print ("获得木头*5!" )
chop_tree()
咔嚓...咔嚓...
获得木头*5!
【chop_tree】动作耗时:2.00 秒
魔法效果: 你不用在 chop_tree 函数里写任何计时的代码,只要穿上 @timer 装备,它自动就拥有计时功能了!超级方便!
应用场景 3:【权限检查】—— 像游戏里的'区域权限' 有些高级操作(比如使用'末影箱'),需要玩家达到 10 级以上才能用。
聪明方法(穿上'权限检查'魔法装备):
做一个'检查装饰器',在执行动作前先检查等级。
player_level = 8
def check_level (required_level ):
def decorator (func ):
def wrapper ():
if player_level >= required_level:
func()
else :
print (f"权限不足!需要 {required_level} 级,你只有 {player_level} 级。" )
return wrapper
return decorator
@check_level(required_level=10 )
def use_ender_chest ():
print ("成功打开末影箱,存取物品!" )
use_ender_chest()
魔法效果: 你把权限检查的代码写在了装饰器里,这样所有需要检查权限的函数,只需要'穿'上这个装备就行了,不用在每个函数里都写一遍 if ... else ...。
微信扫一扫,关注极客日志 微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
curl 转代码 解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online