一.什么是装饰器

顾名思义,装饰器指为其他函数添加新功能

装饰器定义:本质就是函数,功能是为其他函数添加新功能

二.装饰器需要遵循的原则

1.不修改被装饰函数的源代码(开放封闭原则)

2.为被装饰函数添加新功能后,不修改被修改函数的调用方式

3.装饰器的本质 :闭包函数

功能:就是在不改变原函数调用方式的情况下,在这个函数前后加上扩展功能

示例1:

import time
def timmer(func):
#函数名可以当做函数的参数
def inner():
start = time.time()
func()
end = time.time()
print(end - start)
return inner def hahaha():
time.sleep(0.1)
print('aaaa')

示例2:

def timmer(func):  #---> hahaha
def inner(x,y):
func(x,y) # --->hahaha
return inner def hahaha(a,b):
time.sleep(0.1)
print(a,b) def kkk(a):
print(a)

三.装饰器的主要功能和装饰器的固定结构

装饰器的主要功能:

在不改变函数调用方式的基础上在函数的前、后添加功能。

装饰器的固定格式:

def timer(func):
def inner(*args,**kwargs):
'''执行函数之前要做的'''
re = func(*args,**kwargs)
'''执行函数之后要做的'''
return re
return inner

语法糖

import time
def wrapper(func): # 装饰
def inner(*args, **kwargs):
start = time.time()
ret = func(*args, **kwargs)
end = time.time()
print(end - start)
return ret
return inner @wrapper
def lll():
time.sleep(0.1)
print('hello') lll()

 四.

  1.带参数的装饰器

def outer(flag):
def timer(func):
def inner(*args,**kwargs):
if flag:
print('''执行函数之前要做的''')
re = func(*args,**kwargs)
if flag:
print('''执行函数之后要做的''')
return re
return inner
return timer @outer(False)
def func():
print(111) func()
F = False
def outer(flag):
def wrapper(func):
def inner(*args,**kwargs):
if flag:
print('before')
ret = func(*args,**kwargs)
print('after')
else:
ret = func(*args, **kwargs)
return ret
return inner
return wrapper @outer(F) #-->@wrapper -->hahaha = wrapper(hahaha) #-->hahaha == inner
def hahaha():
print('hahaha') @outer(F) #shuangww = outer(shuangww)
def shuangww():
print('shuangwaiwai') shuangww()
hahaha()

2.多个装饰器装饰同一个函数

def qqxing(func):  #func = pipixia_inner
def qqxing_inner(*args,**kwargs):
print('in qqxing:before')
ret = func(*args,**kwargs) #pipixia_inner
print('in qqxing:after')
return ret
return qqxing_inner def pipixia(func): #dapangxie
def pipixia_inner(*args,**kwargs):
print('in pipixia:before')
ret = func(*args,**kwargs) #dapangxie
print('in pipixia:after')
return ret
return pipixia_inner #qqxing(pipixia_inner) -->dapangxie = qqxing_inner()
@qqxing #dapangxie = qqxing(dapangxie) -->dapangxie = qqxing(pipixia(dapangxie)) -->
@pipixia #dapangxie = pipixia(dapangxie)
def dapangxie():
print("饿了么")
dapangxie()

3.开放封闭原则

(1)对扩展是开放的

我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。

(2)对修改是封闭的

就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。

装饰器完美的遵循了这个开放封闭原则。

练习:

'''
编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),
要求登录成功一次,后续的函数都无需再输入用户名和密码
注意:从文件中读出字符串形式的字典,
可以用eval('{"name":"egon","password":"123"}')转成字典格式
'''
# user_dict = {
# 'pang':'123456',
# 'panda':'binbin',
# 'nezha':'101010'
# }
# print(type(user_dic))
auth_status = {
'user':None, #设置全局的字典
'status':False
}
def auth(func):
def inner(*args,**kwargs):
if auth_status['status']: #如果auth_status为真,直接调用就行
ret = func(*args, **kwargs) # index/home
return ret
else:
username = input('username : ').strip()#.strip()避免用户输入带有空格的用户名
password = input('password : ').strip()
# 读文件获取用户信息
f = open('conf') #文件句柄
user_info = f.read() #读取user用户信息
user_dic = eval(user_info) #通过eval转换成字典
if user_dic.get(username) and user_dic[username] == password:#获取字典的k,确认有存在的用户名并找到对应的密码
print('login successful')
auth_status['user'] = username
auth_status['status'] = True
ret = func(*args,**kwargs) #index/home 如果登录成功执行func
return ret
else:
print('login failed')
return inner @auth #装饰器
def index():
print("欢迎来到首页") @auth
def home():
print("欢迎回家") index()
index()
home()
index()
# #认证功能
# #获取用户名和密码
# username = input('username : ').strip()
# password = input('password : ').strip()
# #读文件获取用户信息
# f = open('conf')
# user_info = f.read()
# user_dic = eval(user_info)
# if user_dic.get(username) and user_dic[username] == password:
# print('login successful')
# else:
# print('login failed')
'''
进阶练习:
1.编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果
2.编写装饰器,实现缓存网页内容的功能:
具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),
就优先从文件中读取网页内容,否则,就去下载,然后存到文件中
'''
url_l = []
from urllib.request import urlopen def get_cache(func):
def inner(*args,**kwargs):
url = args[0]
filename = str(hash(url))
if url in url_l:
f = open(filename,'rb')
ret = f.read()
else:
url_l.append(url)
ret = func(*args, **kwargs)
f = open(filename,'wb')
f.write(ret)
f.close()
return ret
return inner @get_cache
def get(url):
return urlopen(url).read() print(get('http://www.cnblogs.com/linhaifeng'))

Python函数之—— 装饰器(Day13)的更多相关文章

  1. Python函数06/装饰器

    Python函数06/装饰器 目录 Python函数06/装饰器 内容大纲 1.装饰器 1.1 开放封闭原则 1.2 装饰器 2.今日练习 内容大纲 1.装饰器 1.装饰器 1.1 开放封闭原则 扩展 ...

  2. python——函数之装饰器

    1 问题 实际生活中,我们很难一次性就把一个函数代码写得完美无缺.当我们需要对以前的函数添加新功能时,我们应该怎么做? 2 问题解决思路 (1)可以直接修改原来的函数,在函数内直接修改.当我们对多个函 ...

  3. python函数、装饰器、迭代器、生成器

    目录: 函数补充进阶 函数对象 函数的嵌套 名称空间与作用域 闭包函数 函数之装饰器 函数之迭代器 函数之生成器 内置函数 一.函数补充进阶 1.函数对象:  函数是第一类对象,即函数可以当作数据传递 ...

  4. Python 函数之装饰器

    1.函数 #### 第一波 #### def foo(): print 'foo' foo #表示是函数 foo() #表示执行foo函数 #### 第二波 #### def foo(): print ...

  5. python函数闭包-装饰器-03

    可调用对象 callable()  # 可调用的(这个东西加括号可以执行特定的功能,类和函数) 可调用对象即  callable(对象)  返回为  True  的对象 x = 1 print(cal ...

  6. Python函数的装饰器修复技术(@wraps)

    @wraps 函数的装饰器修复技术,可使被装饰的函数在增加了新功能的前提下,不改变原函数名称,还继续使用原函数的注释内容: 方便了上下文环境中不去更改原来使用的函数地方的函数名: 使用方法: from ...

  7. Python函数的装饰器修复技术(@wraps)

    @wraps 函数的装饰器修复技术,可使被装饰的函数在增加了新功能的前提下,不改变原函数名称,还继续使用原函数的注释内容: 方便了上下文环境中不去更改原来使用的函数地方的函数名: 使用方法 from ...

  8. Python函数加工厂-装饰器

    引言: 函数和装饰器好比程序界的加工厂: 1.函数一般可用来加工一种或者多种数据类型的数据:字符串.数字.列表.字典等 举一个简单例子:已知半径求面积 def s(r): s = 3.14 * r * ...

  9. Python函数的装饰器

    函数的装饰器. 1. 装饰器 开闭原则: 对功能的扩展开放 对代码的修改是封闭 通用装饰器语法: def wrapper(fn): def inner(*args, **kwargs): # 聚合 & ...

随机推荐

  1. 解决带fusionCharts的页面多次点击后不显示的问题

    问题: 假设不使用公司封装的fusioncharts.使用自己定义的.建议不要使用例如以下方法 使用$(document).ready( 页面载入完之后再载入,会导致多次点击带有fusionchart ...

  2. AudioToolKit的简单介绍及教程

    AudioToolKit的简单介绍及教程 (2013-02-21 09:29:18) 转载▼ 标签: 游戏开发 unity3d教程 unity3d unity it 分类: Unity3d之插件篇 原 ...

  3. HashMap? ConcurrentHashMap?

    前言 Map 这样的 Key Value 在软件开发中是非常经典的结构,常用于在内存中存放数据. 本篇主要想讨论 ConcurrentHashMap 这样一个并发容器,在正式开始之前我觉得有必要谈谈 ...

  4. CSS隐藏滚动条但又能滚动,不用js实现

    隐藏多余的内容,但是可以滑动查看 原理就在于padding-right:17px;把滚动条挤出去隐藏了

  5. pycharm2018.1.4激活破解方法与汉化包-2018年6月19日

    记录下来备用,顺便分享给大家,有能力的还是希望能够支持正版!支持正版!支持正版! 方法1:激活服务器,最简单快速(截止2018年6月19日可用) 在激活Jetbrains旗下任意产品的时候选择激活服务 ...

  6. php 遍历静态html成文章列表

    准备 代码 <?php $root=__DIR__; //全站目录 function my($dir){ static $item_arr=array(); $a=scandir($dir); ...

  7. 通过可编程的对象模型,JavaScript 获得了足够的能力来创建动态的 HTML。

    通过可编程的对象模型,JavaScript 获得了足够的能力来创建动态的 HTML. JavaScript 能够改变页面中的所有 HTML 元素 JavaScript 能够改变页面中的所有 HTML ...

  8. Spring 入门之-dao使用jdbcTemplate(注入过程)

    技巧:在为把dataSourc连接池注入到jdbcTemplate里面时,学到一招:按住CTRL 不松,点击相关类名,可以自动跳转或打开. 说明:主要过程, 1.创建UserDao和UserServi ...

  9. 用记事本写的java程序引用jar文件

    1.将须要用的jar文件和java程序复制到同一个文件文件夹下 2.进行编译.编译的命令:javac -cp log4j-1.2.15.jar A.java 3.进行运行.运行的命令:java -cp ...

  10. Android-ViewPagerIndicator框架使用——TabPageIndicator

    前言:TabPageIndicator这个类和之前的不大一样,他不仅提供了展示的功能,而且可以点击,下面的viewpager可以跳转的有点tabhost的感觉. 一:布局文件的定义,simple_ta ...