Python装饰器就是用于拓展原来函数功能的一种函数,目的是在不改变原函数名(或类名)的情况下,给函数增加新的功能。
装饰器由闭包和语法糖组成。
案例分析:
用户查询商品列表表示业务逻辑
def selectGoods():
print("show the goodsList")
selectGoods()
调用方法名即可。
业务更改:
在查询商品列表之前需要添加权限验证:
def selectGoods():
name = input("check your username")
if name == "pxk":
print("show the goodsList")
else:
print("you cannot look")
selectGoods()
虽然功能实现了,但是改变了原有函数。
在增加新功能的情况下改变原有业务逻辑实现,违背了开闭原则。
使用装饰器:
@函数 是python的一种语法糖。
def check(func):
def check_name():
name = input("check your username:")
if name =="pxk":
func()
else:
print("you cannot look")
return check_name
@check
def selectGoods():
print("show the goodsList")
selectGoods()
使用装饰器之后则selectGoods函数没有发生变化,且功能实现。
@函数名 执行逻辑
检测到需要执行的函数selectGoods 拥有装饰器@check
不执行selectGoods而是将selectGoods 作为参数传入check方法,并且执行check方法 此时func =selectGoods
将check的执行结果返回,即将check_name方法的引用返回,即实际执行的是check_name方法
装饰器调用顺序
装饰器是可以叠加使用的,那么使用装饰器以后代码是啥顺序呢?
对于Python中的”@”语法糖,装饰器的调用顺序与使用 @ 语法糖声明的顺序相反。
def check_username(func):
def check():
name = input("show your username please:")
func()
if name == "pxk":
print("logining...")
else:
print("login failed")
return check
def check_password(func):
def check():
password = input("show your password please:")
if password == "666":
print("login successful!!!")
func()
else:
print("bye!!see you next time!!!")
return check
@check_username
@check_password
def login():
print("welcome!!!")
login()
在这个例子中,”login() = check_username(check_password(login()))”。
Python内置装饰器
在Python中有三个内置的装饰器,都是跟class相关的:staticmethod、classmethod 和property。
1.staticmethod 是类静态方法,其跟成员方法的区别是没有 self 参数,并且可以在类不进行实例化的情况下调用
2.classmethod 与成员方法的区别在于所接收的第一个参数不是 self (类实例的指针),而是cls(当前类的具体类型)
3.property 是属性的意思,表示可以通过通过类实例直接访问的信息
带有参数的装饰器
#如果你的装饰器需要参数,那么给当前的装饰器套一个
#壳子,用于接收装饰器的参数
def ke(a):
def outter(func):
def inner():
print("你读的什么书?")
func()
def inner2():
print("想读什么读什么")
func()
#装饰器壳子的参数,可用于在函数内去做流程控制
if a == "hi":
return inner
else:
return inner2
return outter
@ke("hi")
def read():
print("哈哈")
read()
"""
输出结果:
你读的什么书?
哈哈
"""
装饰带有参数的函数
#定义一个外函数
def outter(func):
#外函数里面包裹一个内函数
def inner(a):#如果装饰器带有参数的函数,需要在内函数中定义形参,并传递给调用的函数,因为调用原函数等于调用内函数
print("你读的什么书?")
#内函数引用外函数的变量
func(a)
print("那好好读这本书吧")
#外函数返回内函数的引用
return inner
@outter
def read(book_name):
print(f"读的{book_name}这本书")
read("Python入门到精通") #read()->inner() read(book_name)->inner(book_name)
print("*******************")
@outter
def read2(book_name):
print(f"读的{book_name}这本书")
read2("Java入门到精通")
"""
输出结果 :
你读的什么书?
读的Python入门到精通这本书
那好好读这本书吧
*******************
你读的什么书?
读的Java入门到精通这本书
那好好读这本书吧
"""
装饰带有多参数的函数
def outter(func):
def inner(book_name,*args):
print("你读的什么书?")
func(book_name,*args)
print("那好好读这本书吧")
return inner
@outter
def read(book_name,*args):
print(f"{book_name}讲了",args)
read("Python从入门到精通",["数据类型","变量","面向对象"],{"面向对象":"封装、继承、多态"})
"""
输出结果:
你读的什么书?
Python从入门到精通讲了 (['数据类型', '变量', '面向对象'], {'面向对象': '封装、继承、多态'})
那好好读这本书吧
"""
类装饰器装饰函数
class Outter:
#魔术方法:当把该类的对象当做函数调用时,自动触发
def __call__(self, func):
self.func = func #把传进来的函数当做对象的成员方法
return self.inner #返回一个函数
def inner(self,name):
self.func(name)
print("你说的对啊!")
@Outter()
def read(book_name):
print(f"{book_name}这本书很好!")
read("Python精通")
"""
输出结果:
Python精通这本书很好!
你说的对啊!
"""