不了解是否其他语言也有类似 python 装饰器这样的东西。

最近才发现ECMAScript6也是有生成器函数的,也有 yield  generator

装饰器的基础知识是闭包:

# 闭包:嵌套函数,内部函数调用外部函数的变量
def outer():
a = 1
def inner():
print(a)
# __closure__ 可以用来判断闭包
# print(inner.__closure__) # 打印 cell at ... 则表明它是一个闭包
return inner # 返回内部函数的内存地址,因为此函数用到了外部函数的变量,所以外部函数的变量也不会因函数的调用结束而消失
inn = outer()
inn() from urllib.request import urlopen
# ret = urlopen('http://www.xiaohua100.cn/index.html').read()
# print(ret) # def get_url():
# url = 'http://www.xiaohua100.cn/index.html'
# ret = urlopen(url).read()
# print(ret)
#
# get_url() # 闭包的简单示例:
# def get_url():
# url = 'http://www.xiaohua100.cn/index.html'
# def get():
# ret = urlopen(url).read()
# print(ret)
# return get # 得到 url 结果
#
# get_func = get_url() # 将结果赋给变量,保存下来。
# get_func()
#

装饰器的作用与原则

import time

def say_hello():
time.sleep(1)
print('hello, everyone...') # 定义一个闭包函数来增加功能
def tmr(f): # 装修器函数
def inner():
start = time.time()
f() # 被装饰函数
end = time.time()
print(end - start) return inner # 传参数的名字,不加括号 fun = tmr(say_hello) # 使用闭包函数
fun() # 装饰器的作用 —— 不想修改函数的调用方式 但是还想在原来的函数前后添加功能
# timmer就是一个装饰器函数,只是对一个函数 有一些装饰作用 # 原则: 开放封闭原则
# 开放 : 对扩展是开放的
# 封闭 : 对修改是封闭的 def deco(f):
def inner(*args, **kwargs):
print('装饰器在函数之前')
ret = f(*args, **kwargs)
print("装饰器在函数之后") return inner @deco
def say_hi():
time.sleep(1)
print('Hi, good morning ...') say_hi()
#!/usr/bin/env python
# coding:utf-8 # 复习一下函数作为参数传递。
# def f11():
# print(12345)
#
#
# def f12(xxx):
# xxx()
#
#
# f12(f11) ## 装修器:本质就是函数,功能是为其他函数添加附加功能
# 原则:
# 1. 不修改被装饰函数的源代码
# 2. 不修改被修饰函数的调用方式 ## 装饰器 = 高阶函数 + 函数嵌套 + 闭包 def outer(func):
def inner():
print('log')
ret = func()
print('after')
return ret
return inner @outer
def f1():
print('F1')
return '砍你哦.' @outer
def f2():
print('F2') @outer
def f100():
print('F100')

在另一个文件中调用上面定义的函数,看看装饰器是否启作用:

#!/usr/bin/env python
# coding:utf-8 import outer01 outer01.f1()
outer01.f2()
outer01.f100()

装饰器简单原理:

#!/usr/bin/env python
# coding:utf-8 def outer(func):
def inner():
print('before')
func()
print('after')
return inner ## 格式 @ + 函数名
## 功能:
# 1. 自动执行outer函数并且将其下面的函数名f1当作参数传递。
# 2. 将outer函数的返回值,重新赋值给f1
@outer
def f1():
print('F1') # 一旦函数被装饰器装饰,函数就会被重新赋值成装饰器函数的内层函数
f1()

换一个文件调用函数:

#!/usr/bin/env python
# coding:utf-8 import outer01 res = outer01.f1() # 也拿到了原函数的返回值。 print(res)

带有参数的装饰器:

#!/usr/bin/env python
# coding:utf-8 import time def timmer(func):
def wrapper(*args, **kwargs):
start_time = time.clock()
res = func(*args, **kwargs)
stop_time = time.clock()
print('运行时间是:%s' % (stop_time - start_time))
return res return wrapper @timmer
def test(name, age):
time.sleep(1)
print('test执行完毕 %s %s' % (name, age))
return 'test complete.' def test2(name, age, gender):
time.sleep(1.2)
print('测试2 %s %d %s' % (name, age, gender)) res = test('alex', 22)
print(res) test2('jerry', 88, 'male')

带参数的装饰器:

#!/usr/bin/env python
# coding:utf-8 user_list=[
{'name':'alex','passwd':''},
{'name':'tom','passwd':''},
{'name':'jerry','passwd':''},
{'name':'kang','passwd':''},
] current_dic = {'username':None,'login':True} def auth(auth_type='filedb'):
def auth_func(func):
def wapper(*args, **kwargs):
print('认证类型是:',auth_type)
if auth_type =='filedb':
if current_dic['username'] and current_dic['login']:
res = func(*args, **kwargs)
return res
username=input('请输入用户名:')
passwd=input('请输入密码:')
for user_dic in user_list:
if username ==user_dic['name'] and passwd == user_dic['passwd']:
current_dic['username'] = username
current_dic['login'] = True
res = func(*args, **kwargs)
return res
else:
print('用户名或密码错误.')
elif auth_type =='ldap':
print('LDAP方式')
res = func(*args, **kwargs)
return res
else:
print('不知道什么方式.')
res = func(*args, **kwargs)
return res
return wapper
return auth_func @auth()
def login():
print("欢迎登录。" ) @auth(auth_type='ldap')
def shopping_cart(name):
print('%s的购物车里有%s %s %s' % (name,'衣服','电池','牛奶')) @auth(auth_type='dsdsds')
def home(name):
print("%s 的主页" % name) login()
shopping_cart('alex')
home('alex')

小练习: 模拟网站增加登录状态验证:

#!/usr/bin/env python
# coding:utf-8 user_dic={'username':None,'login':False} def auth_func(func):
def wapper(*args, **kwargs):
if user_dic['username'] and user_dic['login']:
res = func(*args, **kwargs)
return res
username=input('请输入用户名:')
passwd=input('请输入密码:')
if username =='user' and passwd == '123':
user_dic['username'] = username
user_dic['login'] = True
res = func(*args, **kwargs)
return res
else:
print('用户名或密码错误.')
return wapper @auth_func
def login():
print("欢迎登录。" ) @auth_func
def shopping_cart(name):
print('%s的购物车里有%s %s %s' % (name,'衣服','电池','牛奶')) @auth_func
def home(name):
print("%s 的主页" % name) login()
shopping_cart('alex')
home('alex')

functools 模块中的 wraps

from functools import wraps

def wraper(f):
@wraps(f) # 此内置装饰器保证被装饰的函数的 __name__ 和 __doc__依然不变
def inner(*args,**kwargs):
'''
装饰器内部函数 inner
'''
print('装饰在函数之前')
ret = f(*args,**kwargs)
print('装饰在函数之后')
return ret
return inner @wraper
def holiday(day):
'''
这是一个放假函数
'''
print('公司决定放假{}天'.format(day))
return 'very happy.' # 获取函数名 和 函数文档
print(holiday.__name__) # 装饰器添加之后,结果变成了 inner
print(holiday.__doc__) # 取函数的注释文档
ret = holiday(7)
print(ret)

用装饰器为函数加上调用记录功能,记录每次调用的函数名写入文件

# 用装饰器为函数加上调用记录功能,记录每次调用的函数名写入文件
import time def recd(func):
def inner(*args,**kwargs):
with open('log','a',encoding='utf8') as f:
f.write(time.strftime('%Y-%m-%d %X',time.localtime()) + ' ')
f.write(func.__name__+'\n')
ret = func(*args,**kwargs)
return ret
return inner @recd
def shop_add():
print('增加了一件商品') @recd
def shop_del():
print('删除了某个商品') # print(time.asctime())
# print(time.strftime('%Y-%m-%d %X',time.localtime())) shop_add()
shop_del()

假设有2个装饰器,装饰同一个函数。

那么执行顺序是先执行第一个装饰器的前半部分,再执行第二个装饰器的前半部分,再执行被装饰的函数主体。

主体执行完成后,再执行第二个装饰器的后半部分,最后执行第一个装饰器的后半部分。

#多个装饰器装饰一个函数
def wrapper1(func):
def inner1():
print('wrapper1 ,before func')
ret = func()
print('wrapper1 ,after func')
return ret
return inner1 def wrapper2(func):
def inner2():
print('wrapper2 ,before func')
ret = func()
print('wrapper2 ,after func')
return ret
return inner2 def wrapper3(func):
def inner3():
print('wrapper3 ,before func')
ret = func()
print('wrapper3 ,after func')
return ret
return inner3 @wrapper3
@wrapper2
@wrapper1
def f():
print('in f')
return '哈哈哈' print(f())

python基础16_闭包_装饰器的更多相关文章

  1. Python基础(七) 闭包与装饰器

    闭包的定义 闭包是嵌套在函数中的函数. 闭包必须是内层函数对外层函数的变量(非全局变量)的引用. 闭包格式: def func(): lst=[] def inner(a): lst.append(a ...

  2. Python基础编程闭包与装饰器

    闭包的定义 闭包是嵌套在函数中的函数. 闭包必须是内层函数对外层函数的变量(非全局变量)的引用. 闭包格式: def func(): lst=[] def inner(a): lst.append(a ...

  3. 十一. Python基础(11)—补充: 作用域 & 装饰器

    十一. Python基础(11)-补充: 作用域 & 装饰器 1 ● Python的作用域补遗 在C/C++等语言中, if语句等控制结构(control structure)会产生新的作用域 ...

  4. python基础整理4——面向对象装饰器惰性器及高级模块

    面向对象编程 面向过程:根据业务逻辑从上到下写代码 面向对象:将数据与函数绑定到一起,进行封装,这样能够更快速的开发程序,减少了重复代码的重写过程 面向对象编程(Object Oriented Pro ...

  5. 21.python中的闭包和装饰器

    python中的闭包从表现形式上定义(解释)为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure). 以下说明主要针对 python ...

  6. python中的闭包和装饰器

    重新学习完了函数,是时候将其中的一些重点重新捋一捋了,本次总结的东西只有闭包和装饰器 1.闭包 闭包是python函数中的一个比较重要功能,一般闭包都是用在装饰器上,一般学完闭包就会去学习装饰器,这俩 ...

  7. Python 中的闭包与装饰器

    闭包(closure)是函数式编程的重要的语法结构.闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性. 如果在一个内嵌函数里,对在外部函数内(但不是在全局作用域)的变量进行引用,那么内嵌函数 ...

  8. Python基础(八)装饰器

    今天我们来介绍一下可以提升python代码逼格的东西——装饰器.在学习装饰器之前我们先来复习一下函数的几个小点,方便更好的理解装饰器的含义. 一.知识点复习 1, 在函数中f1和f1()有什么不同,f ...

  9. python基础:10.多线程装饰器模式下的单例模式

    with def __enter__ def __close__ 闭包: 装饰器: 闭包的延迟绑定: 单例模式的应用:

随机推荐

  1. Python入门(二)列表、字典、字符串、元组、集合

    列表list什么是列表:Python内置的一种数据类型是列表,list是一种有序的集合,可以随时添加和删除其中的元素 创建List列表的方法 L = ['杨俊辰',‘啦啦啦’,'Tom'] empty ...

  2. python 写文本文件出现乱码

    最近工作中想完善一下监控日志,同事说客户突然说我们最近几天推送的数据只有几家,赶紧看预警,应推4700多家,实推3400多家,用户可能是看错了,但我记得当时项目验收上线时,这个来源的推送数据肯定是可以 ...

  3. java.nio.file.NoSuchFileException

    springboot +es es 2.1.0 参考这个 https://www.cnblogs.com/yueshutong/p/9381543.html cluster-nodes :改成127. ...

  4. python 装饰器问题及解决方式

    #统计函数运行时间 import time #装饰器 def timmer(func): def wrapper(*args,**kwargs): start_time=time.time() fun ...

  5. oracle 夸服务器、数据库查询

      create public database link 连接名 connect to 需要连接数据库名 identified by  需要连接数据库密码 USING '(DESCRIPTION = ...

  6. JAVA写接口傻瓜(%)教程(五)

    今天主要说一下在URL 中使用?传值的问题.在显式的使用get方法获取特点数据时,一般会通过?传递参数值,sevlert根据参数在数据库中对应的查找内容.所以,SQL语句需要拼接,要加上后面的参数.参 ...

  7. 爬虫(二)Python网络爬虫相关基础概念、爬取get请求的页面数据

    什么是爬虫 爬虫就是通过编写程序模拟浏览器上网,然后让其去互联网上抓取数据的过程. 哪些语言可以实现爬虫    1.php:可以实现爬虫.php被号称是全世界最优美的语言(当然是其自己号称的,就是王婆 ...

  8. iframe的缺点

    *iframe会阻塞主页面的Onload事件: *搜索引擎的检索程序无法解读这种页面,不利于SEO; *iframe和主页面共享连接池,而浏览器对相同域的连接有限制,所以会影响页面的并行加载. 使用i ...

  9. [CentOS] 环境变量设置的三种方法

    在CentOS系统中添加环境变量的方法有几种,推荐第三种方法.这里以添加 TexLive 2017 的环境变量为例进行说明. 1. 修改  ~/.bash_profile  文档,在文末添加以下代码: ...

  10. web前端学习python之第一章_基础语法(二)

    web前端学习python之第一章_基础语法(二) 前言:最近新做了一个管理系统,前端已经基本完成, 但是后端人手不足没人给我写接口,自力更生丰衣足食, 所以决定自学python自己给自己写接口哈哈哈 ...