30 天 Python 学习计划 👨💻 - 第 13 天 - 装饰器
由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!
今天我探索了一个有趣的话题:装饰器。之前我在尝试用 Python 进行面向对象编程时,确实用到过一些装饰器,比如 `@Object`@classmethod和 ` @Object` @staticmethod,但当时并没有深入研究它们。
装饰器是一种编程模式。装饰器本质上就是伪装成装饰器的函数。
使用装饰器,可以为函数添加更多功能或增强其功能。
我将尝试用我自己的浅显易懂的语言解释它们的工作原理以及它们的用途。
许多优秀的 Python 库都大量使用了装饰器,让人感觉它们非常神奇。然而,要理解装饰器,需要先理解一些概念。
履行一等公民的职责
在 Python 中,函数是一等公民。这意味着函数可以像其他数据类型一样赋值给变量,也可以像其他值一样作为参数传递给函数。在 JavaScript 中,函数也有类似的行为,所以我已经熟悉这个概念了。
def multiplier(num1, num2):
return num1 * num2
some_variable = multiplier # (a reference to the function is created)
del multiplier # (deletes the function)
print(some_variable(2,4)) # 8 (still able to call the function!)
在 Python 中,将函数作为值传递的能力对于创建装饰器至关重要。
高阶函数
当满足以下条件时,函数被称为高阶函数:
- 它接受另一个函数作为参数。
- 它返回另一个函数
- 两个都
def logger(func, args): # higher order function
print(f'The result of the passed function is {func(*args)}')
def sum(num1, num2):
return num1 + num2
logger(sum, (1, 5))
def random(): # Higher order function
def special():
print('I am something special')
return special
random_value = random()
random_value() # I am something special
# One line way
random()() # I am something special
定制装饰师
现在,运用以上原则,自定义装饰器看起来会是这样的
def starmaker(func):
'''
A decorator function which accepts a function
and then wraps some goodness into it and
returns it back!
'''
def wrapper():
func()
print('You are a star now!')
print('*********')
return wrapper
@starmaker
def layman():
print('I am just a layman')
layman()
starmaker 装饰器函数赋予了普通函数超能力。它本质上是在函数上添加了一个包装器。现在,任何函数都可以添加@starmaker装饰器,该函数就会变成一颗星!真是太酷了。
Python 解释器能够识别该表达式@decoratorname,并实时将其转换为函数进行处理。上述代码与以下代码块完全相同,只是不使用@decorator语法。
def starmaker(func):
'''
A decorator function which accepts a function
and then wraps some goodness into it and
returns it back!
'''
def wrapper():
func()
print('You are a star now!')
print('*********')
return wrapper
def layman():
print('I am just a layman')
starmaker(layman)() # This is the underlying decorator magic!
起初,我对室内装饰这个概念感到非常困惑。然而,在了解了其基本原理之后,它就变得顺理成章,我也能将其融入到我的思维模式中了。
如果与 JavaScript 相比,JavaScript 语言本身并没有装饰器。然而,作为 JavaScript 超集的 TypeScript 却引入了装饰器的概念。像 Angular 和 NestJS 这样的框架也大量使用了装饰器。
装饰器函数也可以接受参数,并且可以根据传递的参数进行自定义。
def emojifier(func):
def wrapper(emoji):
# kwags are keyword arguments
print(emoji)
func()
return wrapper
@emojifier
def random():
pass
random('😀') # 😀
装饰器有什么用?
装饰器是一种重要的编程模式,如果使用得当,可以带来诸多好处。它能显著提高代码的可重用性,并将新增功能绑定到函数上,从而保持代码的简洁性(DRY 原则)。
# Create an @authenticated decorator that only allows
# the function to run is user1 has 'valid' set to True:
test_user = {
'name': 'Jackson',
'valid': True
}
another_user = {
'name': 'Nathan',
'valid': False
}
def authenticated(fn):
def wrapper(*args, **kwargs):
if args[0]['valid']:
fn(args)
return wrapper
@authenticated
def message_friends(user):
print('message has been sent')
message_friends(test_user) # message has been sent
message_friends(another_user) # (Does nothing)
上述经过身份验证的装饰器函数仅根据指定的条件调用message_friends函数。这提供了很大的灵活性,并可根据用户的身份验证状态执行条件操作。
想了解更多关于Python装饰器的信息,请参考以下文章:
- https://www.programiz.com/python-programming/decorator
- https://realpython.com/primer-on-python-decorators/
今天就到这里。明天我将深入探讨Python中的错误处理技术。又一个重要的主题即将到来。
在此之前,
祝你一切顺利!
文章来源:https://dev.to/arindamdawn/30-days-of-python-day-13-decorators-eg5