【Python】 闭包与装饰器

举报
王建峰 发表于 2021/11/19 03:30:26 2021/11/19
【摘要】 一、闭包 概念:如果在一个函数中,定义了另外一个函数,并且那个函数使用了外面函数的变量,并且外面那个函数返回了里面这个函数的引用,那么称为里面的这个函数为闭包。 def greet(name): def say_hello(): print('hello my name is %s' % ...

一、闭包

概念:如果在一个函数中,定义了另外一个函数,并且那个函数使用了外面函数的变量,并且外面那个函数返回了里面这个函数的引用,那么称为里面的这个函数为闭包。


  
  1. def greet(name):
  2. def say_hello():
  3. print('hello my name is %s' % name)
  4. return say_hello

 

如果想要在闭包中修改外面函数的变量,这时候应该使用nonlocal关键字,来把这个变量标识为外面函数的变量:


  
  1. def greet(name):
  2. def say_hello():
  3. nonlocal name
  4. name += 'hello'
  5. print('hello my name is %s' % name)
  6. return say_hello

 

案例

闭包设计一个计算器


  
  1. def calculator(option):
  2. operator = None
  3. if option == 1:
  4. def add(x,y):
  5. return x+y
  6. operator = add
  7. elif option == 2:
  8. def minus(x,y):
  9. return x-y
  10. operator = minus
  11. elif option == 3:
  12. def multiply(x,y):
  13. return x*y
  14. operator = multiply
  15. else:
  16. def divide(x,y):
  17. return x/y
  18. operator = divide
  19. return operator
  20. cal = calculator(1)
  21. ret = cal(1,2)
  22. print(ret)

 

 

二、装饰器

装饰器利用了函数也可以作为参数传递和闭包的特性,可以让我们的函数在执行之前或者执行之后方便的添加一些代码。

 

理解:网站开发中,经常会碰到一些页面是需要登录后才能访问的。那么如果每次都在访问的视图函数中判断,很麻烦,而且代码很难维护,因此这时候我们可以采用装饰器来解决。

被装饰的函数不带有参数


  
  1. def login_required(func):
  2. def wrapper():
  3. if user['is_login'] == True:
  4. func()
  5. else:
  6. print('跳转到登录页面')
  7. return wrapper
  8. @login_required #相当于 login_required(edit_user)
  9. def edit_user():
  10. print('用户名修改成功')
  11. @login_required #相当于 login_required(add_article)
  12. def add_article():
  13. print('添加文章成功')
  14. edit_user() #相当于 login_required(edit_user)()
  15. add_article() #相当于 login_required(add_article)()

首先,我们把这个判断用户是否登录的逻辑就已经单独抽出放到login_required这个装饰器中了,以后如果某个函数想要做登录限制,那么就先传给login_required这个装饰器就可以了。

然后,在函数定义开头的地方,通过@装饰器名就可以了,这样在调用edit_useredit_user的时候,就不需要手动的传给login_required了。

其中login_required是装饰器;edit_user和edit_user是被装饰函数。

 

被装饰的函数带有参数


  
  1. def login_required(func):
  2. def wrapper(*args,**kwargs):
  3. if user['is_login'] == True:
  4. func(*args,**kwargs)
  5. else:
  6. print('跳转到登录页面')
  7. return wrapper
  8. @login_required
  9. def edit_user(username):
  10. print('用户名修改成功:%s'%username)
  11. edit_user()

采用*args**kwargs组合起来,包含所有的参数

 

带参数的装饰器:


  
  1. def login_required(site='front'):
  2. def outter_wrapper(func):
  3. def inner_wrappre(*args,**kwargs):
  4. if site == 'front':
  5. if user['is_login'] == True:
  6. print('进入到前台了')
  7. func(*args,**kwargs)
  8. else:
  9. print('跳转到前台的首页')
  10. else:
  11. if user['is_login'] == True:
  12. print('进入到后台了')
  13. func(*args,**kwargs)
  14. else:
  15. print('跳转到后台的首页')
  16. return inner_wrappre
  17. return outter_wrapper
  18. @login_required('front')
  19. def edit_user():
  20. print('用户名修改成功')
  21. @login_required('front')
  22. def add_article():
  23. print('添加文章成功')
  24. edit_user()

在原有的装饰器上在加一层闭包 outter_wrapper。

 

wraps装饰器:

采用之前的装饰器,会让我们的函数失去一些属性,比如__name__,这样在一些代码中会产生错误,比如Flask开发中。如果我们想要用装饰器,并且仍想保留函数的一些属性,比如__name__,那么可以使用wraps装饰器


  
  1. from functools import wraps
  2. def login_required(func):
  3. @wraps
  4. def wrapper(*args,**kwargs):
  5. if user['is_login'] == True:
  6. func(*args,**kwargs)
  7. else:
  8. print('跳转到登录页面')
  9. return wrapper
  10. @login_required
  11. def edit_user(username):
  12. print('用户名修改成功:%s'%username)
  13. edit_user()
  14. print(edit_user.__name__)
  15. # 打印edit_user

 

文章来源: blog.csdn.net,作者:hinzer,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/feit2417/article/details/81256599

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。