1、装饰器,基本格式
def shout(word='yes'):
return word.capitalize()
scream=shout
def do_something_before_fun(func):
print("do something before ")
print(func())
do_something_before_fun(scream)
def my_new_decorator(a_function):
def wrapper_fun():
print("before function")
a_function()
print("after function")
return wrapper_fun
@my_new_decorator #语法糖
def another_alone_func():
print("i am alone func")
# func=my_new_decorator(another_alone_func) #@my_new_decorator 是该条语句简写
# func()
another_alone_func()
2、堆积使用装饰器
# 堆积使用装饰器
def bread(func):
def wrapper():
print("</''''''\>")
func()
print("<\______\>")
return wrapper
def ingredients(func):
def wrapper():
print("#tomatoes#")
func()
print("~salad~")
return wrapper
@bread
@ingredients # 相当于:sandwich=bread(ingredients(sandwich))
#装饰器的放置顺序很重要
def sandwich(food="--ham---"):
print(food)
sandwich()
3、给装饰器传递参数
def a_decorator_passing_argus(func):
def a_wrapper_accepting_argus(args1,args2):
print("i got args! look:",args1,args2)
func(args1,args2)
return a_wrapper_accepting_argus
@a_decorator_passing_argus
def print_full_name(args1,args2):
print("my name is :", args1,args2)
print_full_name("li","si")
4、含参数的装饰器
pre_str 是允许参数的装饰器,实际上是对原有装饰器的一个函数封装,并返回一个装饰器。我们可以将他理解为
一个含有环境变量的闭包。当我们使用@pre_str(‘_’)调用的时候,python能够发现这一层的封装,并
把参数传递到装饰器的环境中,该调用相当于:
sum_ab=pre_str(“_”)(sum_ab)
闭包:至少两层楼,楼下变量管上楼,return上楼不动手(不动手即返回函数对象,不带(括号))
装饰器:客人空手来,还得请上楼,干啥都同意,有参给上楼
函数作用域:
1、作用域事栋楼,下楼套上楼
2、读变量,往下搜,一直到一楼
3、该变量,莫下楼,除非你放狗(global)
闭包:函数嵌套,内部函数使用外部函数的变量或者参数,外部函数返回内部函数,这个使用了外部函数变量的内部函数称为闭包
装饰器:实际上也是一个闭包,也是一个函数嵌套;但是装饰器这个闭包函数,他的参数有且只有一个并且是函数类型,这样才是装饰器,否则就是闭包函数
#含参数的装饰器
#新的装饰器层级 def pre_str
def pre_str(pre=""):
#旧的装饰器层级
def decorator(func):
def wrapper(a,b):
print(pre+"input",a,b)
return func(a,b)
return wrapper
return decorator
@pre_str("^_^")
def sum_ab(a,b):
return a+b
print(sum_ab(2,3))
5、装饰类中的方法
python函数和方法几乎是一样的,出了方法的第一个参数是self;装饰器可以装饰函数,就同样可以
装饰类中的方法,记住带上self
装饰类中的方法
def method_decorator(method_to_decorate):
def wrapper(self,line):
line=line-3
return method_to_decorate(self,line)
return wrapper
class lucy():
def __init__(self):
self.age=32
@method_decorator
def say_age(self,line):
print("my age is %s"%(self.age+line))
l=lucy()
l.say_age(-3)
6、通用装饰器
def a_decorator_passing_arguments(func):
def a_wrapper_accepting_arguments(*args, **kwargs):
print("do i have args:?")
print(args)
print(kwargs)
func(*args, **kwargs)
return a_wrapper_accepting_arguments
@a_decorator_passing_arguments
def func_with_no_argument():
print("i have no arguments")
func_with_no_argument()
@a_decorator_passing_arguments
def func_with_argument(a,b,c):
print(a,b,c)
func_with_argument(1,2,3)
@a_decorator_passing_arguments
def func_with_many_arguments(a,b,c,payout="why not"):
print(a,b,c,payout)
func_with_many_arguments(2,3,4,payout="nihao")
class Mary():
def __init__(self):
self.age = 32
@a_decorator_passing_arguments
def say_age(self, line=-3):
print(self.age + line)
m = Mary()
m.say_age()
7、装饰类
装饰器可以接受一个类,并返回一个类,从而起到加工类的效果``
decorator中,返回一个新类newClass,在新类中,记录原来类生成的对象(self.wrapped)
附加了新的属性total_display,用于记录display的次数。同时更改了display方法,通过修改
调用bira类就可以显示调用display的次数了
def decorator(aClass):
class newClass:
def __init__(self,age):
self.total_display=0
self.wrapped=aClass(age)
def display(self):
self.total_display+=1
print("total display",self.total_display)
self.wrapped.display()
return newClass
@decorator
class Bird:
def __init__(self,age):
self.age=age
def display(self):
print("my age is ",self.age)
cl=Bird(5)
for i in range(3):
cl.display()
8、内置装饰器
python中经常用到的三种装饰器,property,static method,classmethod,共同点,作用在类方法上
1、property
property装饰器用于类中的函数,使得我们可以像访问属性一样获取一个函数的返回值
class XiaoHong:
first_name='明'
last_name='小'
@property
def full_name(self):
return self.last_name+self.first_name
xiaohong=XiaoHong()
print(xiaohong.full_name)
2、staticmethod
staticmethod表示被装饰得方法将会是一个静态方法,意味着该方法可以直接被调用,无需实例化,但同样意味着它没有self参数,无法访问实例化后得对象
class XiaoMing:
@staticmethod
def say_hello():
print("同学你好")
XiaoMing.say_hello()
xiaoming=XiaoMing()
xiaoming.say_hello()
3、classmethod
classmethod表示被装饰得方法将会是一个类方法,意味着该方法可以直接被调用 无需实例化,同样意味着没有self参数,也无法访问实例化后得对象。相对于staticmethod得区别是它会接收一个指向类本身得cls参数
class XiaoMing:
name='小明'
@classmethod
def say_hello(cls):
print("你好,我是",cls.name)
print(cls)
XiaoMing.say_hello()
9、wraps装饰器
一个函数不止有执行语句,还有name(函数名),doc(说明文档)等属性,装饰器会导致这些属性改变
运行下方代码,由于装饰器返回了wrapper函数替换掉了之前的say_hello函数,导致函数名,帮助文档变成了wrapper函数的了
def decorator(func):
def wrapper(*args, **kwargs):
"""doc of wrapper"""
print('123')
return func(*args, **kwargs)
return wrapper
@decorator
def say_hello():
"""doc of say hello"""
print('同学你好')
print(say_hello.__name__)
print(say_hello.__doc__)
解决这一问题的办法是通过functools模块下的wraps装饰器
from functools import wraps
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""doc of wrapper"""
print('123')
return func(*args, **kwargs)
return wrapper
@decorator
def say_hello():
"""doc of say hello"""
print('同学你好')
print(say_hello.__name__)
print(say_hello.__doc__)
wrapper使用了通配符,*args代表所有的位置参数,**kwargs代表所有的关键词参数。这样就可以应对任何参数情况。
wrapper调用被装饰的函数的时候,只要原封不动的把参数再传递进去就可以