python3.x 基础三:装饰器
装饰器:本质是函数,用于装饰其他函数,在不改变其他函数的调用和代码的前提下,增加新功能
原则:
1.不能修改被装饰函数的源代码
2.不能修改被装饰函数的调用方式
3.装饰函数对于被装饰函数透明
参考如下链接:
http://egon09.blog.51cto.com/9161406/1836763
实现装饰器的需求:
- 函数即“变量”,函数名指向内存中的函数体,加()表示调用
- 高价函数,将函数当做参数传递给其他函数
- 嵌套函数,在函数体内再定义函数
1.调用简单的函数:
import time
def test1():
time.sleep(1)
print('in the test1')
test1() output:
in the test1
2.在不改变原来函数的定义和调用方式,增加计时功能
import time
def timmer(func):
def warpper(*args,**kwargs):
start_time=time.time()
func()
stop_time=time.time()
print('the func run time is %s' %(stop_time-start_time))
return warpper @timmer
def test1():
time.sleep(1)
print('in the test1')
test1() output:
in the test1
the function run time is -1.0007600784301758:
# /usr/bin/env python
# -*- coding: utf-8 -*-
# Author:Jenvid.yang
# def foo():
# print('in the foo')
# bar()
# foo()
# bar() 未定义,肯定会报错 # def bar():
# print('in the bar')
# def foo():
# print('in the foo')
# bar()
# foo() # def foo():
# print('in the foo')
# bar()
# def bar():
# print('in the bar')
# foo()
# 定义函数的时候,只是用函数名指向内存地址,只要函数执行步骤在函数定义之后即可,各函数间前后关系不影响 # def foo():
# print('in the foo')
# bar()
# foo()
# def bar():
# print('in the bar')
函数名及调用关系
总结1:定义函数的时候,只是用函数名指向内存地址,只要函数执行步骤在函数定义步骤之后即可,各函数间定义先后不影响,与变量定义先后一个道理
高阶函数
1.把一个函数名当做实参传给另外一个函数--实现装饰器:不修改被装饰函数下,给源代码,也就是被装饰函数增加新功能
2.返回值中包含函数名--实现装饰器:不修改函数的调用方式
- 函数返回实参函数内存地址
def bar():
print('in the bar')
def test1(func):
print(func)
test1(bar)
print('分割线'.center(,'-'))
def test2(func):
return func
fff=test2(bar) # 将内存地址,也就是函数体,也就是test2返回值,赋值给一个变量
fff() # 变量加上(),表示调用
output:
<function bar at 0x7f5fa0a7d730>
-------------分割线--------------
in the bar
- 高阶函数传参方式实现源代码bar没有被更改,调用方式被更改了
import time
def bar():
time.sleep(1)
print('in the bar')
def test1(func):
start_time=time.time()
func()
stop_time=time.time()
print('the function run time is %s' % (stop_time-start_time))
test1(bar)
output:
in the bar
the function run time is 1.0011107921600342
#被调用函数原来调用方式是:bar(),函数体里面的内容也没有更改
#新的函数是test1,调用的是test1(),改变了调用函数名,如果有生产线上已经在调用bar(),这种情况下意味着所有的调用bar函数的其他函数,都需要将bar改成test1
- 高阶函数返回值方式实现函数调用方式不更改
import time
def bar():
time.sleep()
print('in the bar')
def test1(func):
start_time=time.time()
return func
stop_time=time.time()
print('the function run time is %s' % (stop_time-start_time))
bar=test1(bar)
bar()
output:
in the bar
# 高阶函数返回内存地址实现调用方式不更改,但函数的新功能又没加上
- 嵌套函数,在高阶函数下,给新功能函数增加多一层函数嵌套
import time
def bar():
time.sleep(1)
print('in the bar')
def timmer(func):
def test1():
start_time=time.time()
func()
stop_time=time.time()
print('the function run time is %s' % (stop_time-start_time))
return test1 #返回test1的内存地址
bar=timmer(bar) #将bar函数地址作为实参传递给timmer函数的形参func,func将在嵌套函数test1里面进行调用
bar() #此时的bar其实是timmer函数地址,并不是原来的bar
output:
in the bar
the function run time is 1.0010881423950195
- 语法糖
import time
def timmer(func):
def test1():
start_time=time.time()
func()
stop_time=time.time()
print('the function run time is %s' % (stop_time-start_time))
return test1
# bar=timmer(bar)
@timmer #只需要在被调用函数的前面用关键字符“@装饰器函数”,既可以实现装饰器效果
def bar():
time.sleep(1)
print('in the bar')
bar()
output:
in the bar
the function run time is 1.0011053085327148
import time
def timmer(func):
def warpper(): #一般将装饰器嵌套函数名命名为warpper 据说懂了这个可以解决90%的问题
start_time=time.time()
func()
stop_time=time.time()
print("the function run time is %s:" %(start_time-stop_time))
return warpper
@timmer #这里还是相当于更改被装饰函数的’变量名‘内存地址 bar=timmer(bar)
def bar():
time.sleep(1)
print('in the bar')
bar()
- 装饰器参数传值-被装饰函数传1个值
import time
def timmer(func):
def warpper(name):
start_time=time.time()
func(name)
stop_time=time.time()
print("the function run time is %s:" %(start_time-stop_time))
return warpper
@timmer
def test1(name):
time.sleep()
print('in the test1 %s',name)
test1('alex')
output:
in the test1 %s alex
the function run time is -1.0006732940673828:
- 装饰器参数传值-被装饰函数传2个值
import time
def timmer(func):
def warpper(name,age):
start_time=time.time()
func(name,age)
stop_time=time.time()
print("the function run time is %s:" %(start_time-stop_time))
return warpper
@timmer
def test1(name,age):
time.sleep()
print('in the test1 name is %s,age is %d'%(name,age))
test1('alex',)
output:
in the test1 name is alex,age is 18
the function run time is -1.000108003616333:
- 装饰器参数传值-被装饰函数传n个值
import time
def timmer(func):
# print('func timmer')
def wrapper(*args,**kwargs):
print('打印实参:',args,kwargs)
start_time=time.time()
func(*args,**kwargs)
stop_time=time.time()
print("the function run time is %s:" % (stop_time-start_time))
return wrapper
@timmer
# test1=timmer(test1)
def test1(name,age):
time.sleep()
print('in the test1 func, name is %s,age is %d' % (name,age))
test1('alex',) @timmer
# test1=timmer(test1)
def test2(name,age,sex,salary):
time.sleep()
print('in the test1 func, name is %s,age is %d,sex is %s,salary is %d' % (name,age,sex,salary))
test2('alex',,'man',)
output:
打印实参: ('alex', 18) {}
in the test1 func, name is alex,age is 18
the function run time is 1.0013768672943115:
打印实参: ('alex', 18, 'man', 3000) {}
in the test1 func, name is alex,age is 18,sex is man,salary is 3000
the function run time is 1.0012915134429932:
- 试错过程:
import time
def timmer(func):
def warpper():
# print('打印实参:',args,kwargs)
start_time=time.time()
func()
stop_time=time.time()
print("the function run time is %s:" % (stop_time-start_time))
return warpper
@timmer #这里相当于test1=timmer(test1)=wrapper,test1加上参数相当于test1(name,age)=wrapper(name,age)
def test1(name,age):
time.sleep()
print('in the test1 name is %s,age is %s'%(name,age))
test1('alex',)
输出如下:
/usr/bin/python3. /root/PycharmProjects/S14/day04/bin/decoreate03.py
Traceback (most recent call last):
File "/root/PycharmProjects/S14/day04/bin/decoreate03.py", line , in <module>
test1('alex',)
TypeError: warpper() takes positional arguments but were given Process finished with exit code 1
step1:定义装饰器函数体timmer
step2:语法糖,调用装饰器函数,准备装饰下一行函数,返回内层嵌套函数变量warpper内存地址
step3:定义函数体test1
step4:调用函数test1,将test1作为实参,传递给装饰器timmer
step5:warpper函数调用,需要讲test1的实参传递给wrapper,由于命名空间关系,test1的参数无法传递到warpper,func也无法获得实参- 给包装函数warrper增加形参
import time
def timmer(func):
def warpper(name,age):
# print('打印实参:',args,kwargs)
start_time=time.time()
func()
stop_time=time.time()
print("the function run time is %s:" % (stop_time-start_time))
return warpper
@timmer #test1=timmer(test1)
def test1(name,age):
time.sleep(1)
print('in the test1 name is %s,age is %s'%(name,age))
test1('alex',18)
输出如下
/usr/bin/python3.5 /root/PycharmProjects/S14/day04/bin/decoreate03.py
Traceback (most recent call last):
File "/root/PycharmProjects/S14/day04/bin/decoreate03.py", line 17, in <module>
test1('alex',18)
File "/root/PycharmProjects/S14/day04/bin/decoreate03.py", line 9, in warpper
func()
TypeError: test1() missing 2 required positional arguments: 'name' and 'age'
这个解释很明显,func就是test1,缺少了2个位置参数,把func()改成func(name,age)即正确
# /usr/bin/env python
# -*- coding: utf-8 -*-
# Author:Jenvid.yang
import time
def timmer(func): #func=test2
def wrapper(*args,**kwargs):
start_time=time.time()
func(*args,**kwargs)
stop_time=time.time()
print('func run time is %s' %(stop_time-start_time))
return wrapper @timmer
def bar():
time.sleep(1)
print('in the bar')
bar()
@timmer #test2=timmer(test2)=warpper ->test2(name)=warpper(name)
def test2(name):
time.sleep(1)
print('in the test2',name)
test2('alex')课堂分析源码
- 被装饰函数如果带有返回值的情况
import time
def timmer(func):
# print('func timmer')
def wrapper(*args,**kwargs):
print('打印实参:',args,kwargs)
start_time=time.time()
func(*args,**kwargs)
stop_time=time.time()
print("the function run time is %s:" % (stop_time-start_time))
return wrapper
@timmer
# test1=timmer(test1)
def test1(name,age,address):
time.sleep(1)
print('in the test1 func, name is %s,age is %d,address is %s' % (name,age,address))
test1('alex',18,'nuber001')
# @timmer
# test1=timmer(test1)
def test3(name,age,sex,salary):
time.sleep(1)
# print('in the test1 func, name is %s,age is %d,sex is %s,salary is %d' % (name,age,sex,salary))
return (name,age,sex,salary)
print(test3('alex',18,'man',3000))
输出如下:
/usr/bin/python3.5 /root/PycharmProjects/S14/day04/decoreate02.py
打印实参: ('alex', 18, 'nuber001') {}
in the test1 func, name is alex,age is 18,address is nuber001
the function run time is 1.0009291172027588:
('alex', 18, 'man', 3000) Process finished with exit code 0
函数test1,没有返回值,装饰后正常输出
函数test2,带有返回值,没有装饰,打印了实参元组
如果test2装饰后呢?
import time
def timmer(func):
# print('func timmer')
def wrapper(*args,**kwargs):
print('打印实参:',args,kwargs)
start_time=time.time()
func(*args,**kwargs)
stop_time=time.time()
print("the function run time is %s:" % (stop_time-start_time))
return wrapper
@timmer
# test1=timmer(test1)
def test1(name,age,address):
time.sleep(1)
print('in the test1 func, name is %s,age is %d,address is %s' % (name,age,address))
test1('alex',18,'nuber001')
@timmer
# test1=timmer(test1)
def test3(name,age,sex,salary):
time.sleep(1)
# print('in the test1 func, name is %s,age is %d,sex is %s,salary is %d' % (name,age,sex,salary))
return (name,age,sex,salary)
print(test3('alex',18,'man',3000))
输出如下:
打印实参: ('alex', 18, 'nuber001') {}
in the test1 func, name is alex,age is 18,address is nuber001
the function run time is 1.0010955333709717:
打印实参: ('alex', 18, 'man', 3000) {}
the function run time is 1.0010552406311035:
None
带有返回值的test2被装饰后,变成了None,改变了原函数的输出,这是不允许的 给包装函数中的调用原函数增加赋值和返回值:
import time
def timmer(func):
# print('func timmer')
def wrapper(*args,**kwargs):
print('打印实参:',args,kwargs)
start_time=time.time()
res=func(*args,**kwargs) #用一个变量保存原函数输出值
stop_time=time.time()
print("the function run time is %s:" % (stop_time-start_time))
return res #返回原函数结果给wrapper
return wrapper
@timmer
# test1=timmer(test1)
def test1(name,age,address):
time.sleep(1)
print('in the test1 func, name is %s,age is %d,address is %s' % (name,age,address))
test1('alex',18,'nuber001')
@timmer
# test1=timmer(test1)
def test3(name,age,sex,salary):
time.sleep(1)
# print('in the test1 func, name is %s,age is %d,sex is %s,salary is %d' % (name,age,sex,salary))
return (name,age,sex,salary)
print(test3('alex',18,'man',3000))
输出如下:
打印实参: ('alex', 18, 'nuber001') {}
in the test1 func, name is alex,age is 18,address is nuber001
the function run time is 1.0010664463043213:
打印实参: ('alex', 18, 'man', 3000) {}
the function run time is 1.0010428428649902:
('alex', 18, 'man', 3000)
- 语法糖带参数情况,index使用本地验证,home使用ldap验证,同一个装饰器,如何实现不同的验证方式?
def deco(func):
def wrapper(username,password):
print('I am 包装1')
func(username,password)
print('I am 包装2')
return wrapper
@deco(auth_type='local')
def index(username,password):
print('welcome to index page',username)
index('yzw','secret')
@deco(auth_type='ldap')
def home(username,password):
print('welcome to home page',username)
home('alex','secret')- 再嵌套一层函数
def auth(auth_type):
def out_wrapper(func):
def wrapper(username,password):
if auth_type == 'local':
print('via local certification')
print('I am 包装前')
func(username,password)
print('I am 包装后')
elif auth_type == 'ldap':
print('嘻嘻嘻嘻')
func(username, password)
print('via ldap certfication')
return wrapper
return out_wrapper
@auth(auth_type='local')
#1.全部不带参数,相当于index=deco(index)
#2.被装饰函数带参数,相当于index=deco(index)=wrapper ->index(args)=wrapper(args)
#3.语法糖带参数,就需要多嵌套一层外层函数,将语法糖的参数传递给这一外层函数
def index(username,password):
print('welcome to index page <local>',username)
index('yzw','secret')
@auth(auth_type='ldap')
def home(username,password):
print('welcome to home page <ldap>',username)
home('alex','secret')
输出如下:
/usr/bin/python3.5 /root/PycharmProjects/S14/day04/bin/decorate04.py
via local certification
I am 包装前
welcome to index page <local> yzw
I am 包装后
嘻嘻嘻嘻
welcome to home page <ldap> alex
via ldap certfication Process finished with exit code 0#/usr/bin/env python
#-*- coding: utf-8 -*-
#Author:jenvid.yang
def auth(auth_type):
def out_wrapper(func):
def wrapper(*args,**kwargs):
if auth_type == 'local':
print('via local certification')
func(*args,**kwargs)
elif auth_type == 'ldap':
print('via ldap certfication')
func(*args, **kwargs)
return wrapper
return out_wrapper
@auth(auth_type='local')
#1.全部不带参数,相当于index=deco(index)
#2.被装饰函数带参数,相当于index=deco(index)=wrapper ->index(args)=wrapper(args)
#3.语法糖带参数,就需要多嵌套一层外层函数,将语法糖的参数传递给这一外层函数
def index(username,password):
print('welcome to index page <local>',username)
index('yzw','secret')
@auth(auth_type='ldap')
def home(username,password):
print('welcome to home page <ldap>',username)
home('alex','secret')改成万能参数
# /usr/bin/env python
# -*- coding: utf-8 -*-
# Author:Jenvid.yang
import time
user,passwd='alex','abc123'
def auth(auth_type):
print('auth func:',auth_type)
def outer_wrapper(func):
def wrapper(*args,**kwargs):
print('wrapper func args:',*args,**kwargs)
if auth_type == 'local':
username=input('username:').strip()
password=input('password:').strip()
if user == username and passwd == password:
print('\033[32;1m user has passed authentication \033[0m')
res = func(*args,**kwargs)
print('xxxxx')
return res
else:
exit('\033[31;1m invalid username or password \033[0m')
elif auth_type == 'ldap':
print('xxxx')
return wrapper
return outer_wrapper
# @auth
def index():
print('welcome to index page')
@auth(auth_type='local') #home=wrapper()
def home():
print('welcom to home page')
return ('from home')
# 函数结果被改变
@auth(auth_type='ldap')
def bbs():
print('welcome to bbs page') index()
print(home()) # wrapper()
bbs()课堂分析源码
python3.x 基础三:装饰器的更多相关文章
- python3【基础】-装饰器
要理解充分理解python的装饰器,有充分理解下述三个知识点为前提: python作用域规则 函数即对象 闭包 一.python作用域规则: 首先介绍python中的作用域规则.python的作用域规 ...
- 函数基础(三) 装饰器\闭包 day 12
目录 昨日回顾 可变长参数 * ** 函数对象 函数嵌套 名称空间和作用域 今日内容 闭包函数 装饰器 语法糖 装饰器模板 迭代器 昨日回顾 可变长参数 * *形参:接受多余的位置实参 *实参(可迭代 ...
- python基础—函数装饰器
python基础-函数装饰器 1.什么是装饰器 装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能. 装饰器的返回值是也是一个函数对象. 装饰器经常用于有切 ...
- 十. Python基础(10)--装饰器
十. Python基础(10)--装饰器 1 ● 装饰器 A decorator is a function that take a function as an argument and retur ...
- Python3基础笔记--装饰器
装饰器是十二分重要的高级函数. 参考博客:装饰器 所需前提知识: 1.作用域: LEGB 2.高阶函数 高阶函数是至少满足下列一个条件的函数: 1)接受一个或多个函数作为输入 2)输出一个函数 注意理 ...
- python基础之装饰器(实例)
1.必备 #### 第一波 #### def foo(): print 'foo' foo #表示是函数 foo() #表示执行foo函数 #### 第二波 #### def foo(): print ...
- 【Python基础】装饰器的解释和用法
装饰器的用法比较简单,但是理解装饰器的原理还是比较复杂的,考虑到接下来的爬虫框架中很多用到装饰器的地方,我们先来讲解一下. 函数 我们定义了一个函数,没有什么具体操作,只是返回一个固定值 请注意一下缩 ...
- 学习PYTHON之路, DAY 5 - PYTHON 基础 5 (装饰器,字符格式化,递归,迭代器,生成器)
---恢复内容开始--- 一 装饰器 1 单层装饰器 def outer(func): def inner(): print('long') func() print('after') return ...
- [python基础]关于装饰器
在面试的时候,被问到装饰器,在用的最多的时候就@classmethod ,@staticmethod,开口胡乱回答想这和C#的static public 关键字是不是一样的,等面试回来一看,哇,原来是 ...
随机推荐
- GDI+ 绘制砂岩含量图版
图版是在工作中经常会使用到的工具,它能够大大提高我们日常工作效率.地质图版在地质工作中具有举足轻重的作用,不仅可以轻松判断岩性,也可以依据经验图版直接得到结果,十分方便. 本程序目的绘制出一个地质常用 ...
- QML-密码管理器
Intro 年初刚学Qml时写的密码管理器.用到Socket通信.AES加密等.UI采用Material Design,并实现了Android App的一些常见基本功能,如下拉刷新.弹出提示.再按一次 ...
- JAVA进程CPU高的解决方法
无限循环的while会导致CPU使用率飙升吗?经常使用Young GC会导致CPU占用率飙升吗?具有大量线程的应用程序的CPU使用率是否较高?CPU使用率高的应用程序的线程数是多少?处于BLOCKED ...
- for-loop 与 json.Unmarshal 性能分析概要
原文地址:for-loop 与 json.Unmarshal 性能分析概要 前言 在项目中,常常会遇到循环交换赋值的数据处理场景,尤其是 RPC,数据交互格式要转为 Protobuf,赋值是无法避免的 ...
- composer+psr-4实现自动加载
自动加载 对于库的自动加载信息,Composer 生成了一个 vendor/autoload.php 文件.你可以简单的引入这个文件,你会得到一个免费的自动加载支持. require 'vendor/ ...
- SAP WM TO Print Control设置里,Movement Type 的优先级更高
SAP WM TO Print Control设置里,Movement Type 的优先级更高 存储类型的配置: 从storage type GRM 搬到任何地方,都不需要打印TO单. 移动类型的配置 ...
- servlet温故知新
重新学习了一遍servlet-api的文档,做一些记录. 有道云的笔记直接复制到博客上格式会乱,因此直接放上有道云的链接:http://note.youdao.com/noteshare?id=915 ...
- 第十届山东省赛L题Median(floyd传递闭包)+ poj1975 (昨晚的课程总结错了,什么就出度出度,那应该是叫讨论一个元素与其余的关系)
Median Time Limit: 1 Second Memory Limit: 65536 KB Recall the definition of the median of elements w ...
- libevhtp初探
libevent的evhttp不适合多线程,libevhtp重新设计了libevent的http API,采用了和memcached类似的多线程模型. worker线程的管道读事件的回调函数为htp_ ...
- socket编程之并发回射服务器2
承接上文:socket编程之并发回射服务器 为了让服务器进程的终止一经发生,客户端就能检测到,客户端需要能够同时处理两个描述符:套接字和用户输入. 可以使用select达到这一目的: void str ...