30天学习Python👨💻第十三天——装饰器
今天我探索了一个有趣的主题,装饰器。在探讨面向对象编程时,我使用了两个装饰器,@classmethod 和@staticmethod。然而,我当时并没有详细地去讲。
装饰器是一种编程模式,装饰器是简化版的伪装函数。
使用装饰器给函数添加更多的功能或者使它们更加强大成为了可能。大量的Python库广泛使用装饰器,让人们觉得很神奇。但是,理解装饰器之前还有一些概念需要先理解。
函数是一等公民
在Python中函数是一等公民,这意味着函数可以像其他数据类型一样作为参数传给其他函数,也可以像其他数据类型一样作为函数的返回值。在JavaScript里函数也是类似的,因此我把它们联系了起来。
def multiplier(num1, num2):
return num1 * num2
some_variable = multiplier # (创建了一个函数引用)
del multiplier # (删除一个函数)
print(some_variable(2,4)) # 8 (函数仍然能够被调用!)
在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(): # 高阶函数
def special():
print('I am something special')
return special
random_value = random()
random_value()
# 只用一行的方式,与上面两行的功能一样
random()()
自定义装饰器
根据上面的原则,一个装饰器看起来应该是这个样子:
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 装饰器函数赋予了layman 函数更强大的功能。它基本是在函数上添加了一个包装器。现在装饰器@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)()
一开始接触装饰器的时候我也感到很疑惑。但是当我搞清楚它的基本原理之后,它对我就变得特别自然,我把它加入到了我的知识体系中。
如果和JavaScript对比,JavaScript语言中没有装饰器的存在。但是,JavaScript的超集TypeScript中是有装饰器的。像Angular,NestJS这样的框架重度使用装饰器。
一个装饰器函数能够接受参数,并且能够根据传递的参数进行定制。
def emojifier(func):
def wrapper(emoji):
print(emoji)
func()
return wrapper
@emojifier
def random():
pass
random('😀') # 😀
为什么装饰器这么有用
装饰器是一种非常重要的编程模式,如果使用得当,它能带来很多好处。它能使代码具有高可重用性,并将添加的功能绑定到函数中,保证了编程的DRY原则。
# 创造一个@authenticated装饰器
# 要运行的函数是对象的'valid'设置为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) # (什么的都不做)
上面经过身份验证的装饰器函数只根据指定的条件调用message_friends函数。这提供了很大的灵活性,并根据用户身份验证的状态执行条件操作。
Python装饰器的参考文章:
这就是今天的全部了。明天我将继续探讨Python中关于错误处理技术,这是接下来另一个重要的主题。