装饰器详解
函数刚开始不解析内部,只是放进内存
装饰器是函数,只不过该函数可以具有特殊的含义,装饰器用来装饰函数或类,使用装饰器可以在函数执行前和执行后添加相应操作。
1 下面以一个函数开始,理解下面概念
1 def foo(): 2 print 'foo' 3 4 foo 是函数 5 foo() 是执行函数
2 看下面的一个函数执行过程
1 def f1(arg): 2 arg() 3 4 def func(): 5 print '123' 6 7 f1(func)
3 上面的理解之后,看下面一个函数执行过程
1 def auth(func): 2 def wrapper(): 3 print "before" 4 func() 5 return wrapper 6 def f1(): 7 print "f1" 8 auth(f1)
4 接着上边的,如何执行内部的内容, 引入装饰器
还是上面的函数,换了执行方式
1 def auth(func): 2 def wrapper(): 3 print "before" 4 func() 5 return wrapper 6 def f1(): 7 print "f1" 8 ret=auth(f1) 9 ret()
5 装饰器引入
1 def auth(func): 2 def wrapper(): 3 print "before" 4 func() 5 return wrapper 6 7 @auth 8 def f1(): 9 print "f1 10 11 @auth=>auth(f1)==>f1=auth(f1)=def wrapper(): 12 print "before" 13 func() 14 接下来再执行f1()就相当于执行了wrapper()函数
主要过程是执行auth函数,被装饰的函数作为参数传入auth--auth(f1),auth函数的返回值,赋值给被装饰的函数的函数名,---f1=wrapper
6 装饰器含参数(一个参数)
1 def auth(func): 2 def inner(arg): 3 print "before" 4 func(arg) 5 return inner 6 @auth 7 def f2(arg): 8 print "f2" ,arg 9 f2('test') 10 11 结果 12 before 13 f2 test
7 多个参数,动态参数
1 def auth(func): 2 def inner(*args,**kwargs): 3 print "before" 4 func(*arg,**kwargs) 5 print 'after' 6 return inner 7 8 @auth 9 def f2(*args,**kwargs): 10 print "f2" 11 12 f2('1.1.1.1')
8 含有返回值的装饰器
1 def auth1(func): 2 def inner(*arg,**kwargs): 3 print 'before' 4 temp = func(*arg,**kwargs) 5 print 'after' 6 return temp #inner函数有了返回值 7 return inner 8 9 @auth1 10 def fetch_list(arg): 11 print "fetch_list" 12 server_list = [11,22,33] 13 return server_list 14 15 ret = fetch_list('test') 16 print ret 17 18 结果 19 before 20 fetch_list 21 after 22 [11, 22, 33]
9 装饰器实现登录验证
主要就是增加了一个login函数
1 def login(): 2 name = 'dicky' 3 if name == 'dicky1': 4 return True 5 else: 6 return False 7 8 def auth3(func): 9 def inner(*args,**kwargs): 10 is_login = login() 11 if not is_login: 12 return "invild" 13 temp = func(*args,**kwargs) 14 return temp 15 return inner 16 @auth3 17 def fetch_list(arg): 18 print "fetch_list" 19 server_list = [11,22,33] 20 return server_list 21 ret=fetch_list('test') 22 print ret 23 24 结果 25 invild
10 装饰器实现token验证,跟上面的login差不多
1 def login1(key): 2 name = 'alex1' 3 local = 'afcadfsgdgwegsfbdfgsgsfwe' 4 if local == key: 5 return True 6 else: 7 return False 8 def auth3(func): 9 def inner(*arg,**kwargs): 10 # key=kwargs['token'] 11 # del kwargs['token'] 12 key = kwargs.pop('token') #删除多传入的参数 13 is_login = login1(key) 14 if not is_login: 15 return "invild" 16 print 'before' 17 temp = func(*arg,**kwargs) #上面删除了多传入的参数,这里就不会报错了 18 print 'after' 19 return temp 20 return inner 21 22 @auth3 23 def fetch_list(arg): 24 print "fetch_list" 25 server_list = [11,22,33] 26 return server_list 27 28 key = 'afcadfsgdgwegsfbdfgsgsfwe' 29 ret = fetch_list('test',token=key) 30 print "llllllllll" 31 print ret
11 多装饰器
先执行外部装饰器,然后在执行内部装饰器
1 def w1(func): 2 def inner(): 3 print 'w1 before' 4 func() 5 print 'w1 after' 6 return inner 7 def w2(func): 8 def inner(): 9 print 'w2 after' 10 func() 11 print 'w2 after' 12 return inner 13 @w2 14 @w1 15 def foo(): 16 print 'foo' 17 18 foo() 19 结果 20 w2 after 21 w1 before 22 foo 23 w1 after 24 w2 after
12 装饰器附加参数
1 def Before(request,kargs): 2 print 'before' 3 4 def After(request,kargs): 5 print 'after' 6 7 8 def Filter(before_func,after_func): 9 def outer(main_func): 10 def wrapper(request,kargs): 11 12 before_result = before_func(request,kargs) 13 if(before_result != None): 14 return before_result; 15 16 main_result = main_func(request,kargs) 17 if(main_result != None): 18 return main_result; 19 20 after_result = after_func(request,kargs) 21 if(after_result != None): 22 return after_result; 23 24 return wrapper 25 return outer 26 27 @Filter(Before, After) 28 def Index(request,kargs): 29 print 'index'
过程如下
@Filter(Before, After)
先执行Filter(Before, After)函数,获取返回值ret,获取返回值后,拼接成@ret,也就是相当于引入了两个参数,以至于后来可以使用这两个参数。
13 functools.wraps 的作用
上述的装饰器虽然已经完成了其应有的功能,即:装饰器内的函数代指了原函数,注意其只是代指而非相等,原函数的元信息没有被赋值到装饰器函数内部。例如:函数的注释信息
看下面的两个例子
def outer(func): def inner(*args, **kwargs): print(inner.__doc__) # None return func() return inner @outer def function(): """ asdfasd :return: """ print('func') function()
结果
None #并没有输出__doc__的信息
加上@functools.wraps之后
import functools
1 def outer(func): 2 @functools.wraps(func) 3 def inner(*args, **kwargs): 4 print(inner.__doc__) # None 5 return func() 6 return inner 7 8 @outer 9 def function(): 10 """ 11 asdfasd 12 :return: 13 """ 14 print('func') 15 16 function() 17 结果 18 asdfasd 19 :return: 20 21 func 22 23 #输出了原函数的__doc__内容
二 递归
1 编写数列

1 斐波那契数列指的是这样一个数列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368
函数如下

1 def func(arg1,arg2): 2 if arg1==0: 3 print arg1,arg2 4 arg3=arg1+arg2 5 print arg3 6 func(arg2,arg3) 7 8 9 func(0,1)
2 递归的返回值
先看下面的一个简单例子
1 def n5(): 2 return '1234' 3 def n4(): 4 n5() 5 def n3(): 6 n4() 7 def n2(): 8 n3() 9 def n1(): 10 n2() 11 ret=n1() 12 print ret 13 14 结果None
分析如下
上面的函数首先执行
n1()---n2()--n3()---n4()--n5()
到执行到n5的时候有返回值,n5函数的返回值返回给调用n5函数的函数n4
即res=n5()----def n4(): 但是n4没有返回值,n3也没有返回值,n2也没有返回值,n1也没有返回值,所以最后返回none
改进一下,让他有返回值

1 def n5(): 2 return '1234' 3 def n4(): 4 return n5() 5 def n3(): 6 return n4() 7 def n2(): 8 return n3() 9 def n1(): 10 return n2() 11 ret=n1() 12 print ret 13 14 15 结果 16 1234 17 这样让它每次都有返回值
3 看下面的递归例子(改进了一下上边的数列例子)
1 def func(arg1,arg2): 2 if arg1==0: 3 print arg1,arg2 4 arg3=arg1+arg2 5 if arg3>1000: 6 return arg3 7 func(arg2,arg3) 8 9 ret = func(0,1) 10 print ret 11 12 结果为None
分析如下
执行第一次func(0,1)没有返回值
执行第二次func(1,1)也没有返回值
..........
当执行到func(610,987)的时候,接着执行上面,arg=1597,满足条件,return返回1597,谁调用的返回给谁,也就是返回给func(610,987),但是在这之前执行func()函数却没有返回值,跟上面的例子差不多,所以最后返回None
改进之后:

1 def func(arg1,arg2): 2 if arg1==0: 3 print arg1,arg2 4 arg3=arg1+arg2 5 if arg3>1000: 6 return arg3 7 return func(arg2,arg3) 8 9 ret = func(0,1) 10 print ret 11 12 结果 13 1597
三模块
模块分为三种:
- 自定义模块
- 内置模块
- 开源模块
自定义模块
1
2
导入模块
1 import module 2 from module.xx.xx import xx 3 from module.xx.xx import xx as rename 4 from module.xx.xx import *
导入模块其实就是告诉Python解释器去解释那个py文件
- 导入一个py文件,解释器解释该py文件
- 导入一个包,解释器解释该包下的 __init__.py 文件
1 模块路径 2 import sys 3 print sys.path 4 结果 5 ['F:\untitled5\test', 'F:\untitled5', 'C:\Windows\system32\python27.zip', 'C:\Python27\DLLs', 'C:\Python27\lib', 'C:\Python27\lib\plat-win', 'C:\Python27\lib\lib-tk', 'C:\Python27', 'C:\Python27\lib\site-packages', 'C:\Python27\lib\site-packages\pip-9.0.1-py2.7.egg']
常用内置模块
os模块

1 os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 2 os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd 3 os.curdir 返回当前目录: ('.') 4 os.pardir 获取当前目录的父目录字符串名:('..') 5 os.makedirs('dirname1/dirname2') 可生成多层递归目录 6 os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推 7 os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname 8 os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname 9 os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印 10 os.remove() 删除一个文件 11 os.rename("oldname","newname") 重命名文件/目录 12 os.stat('path/filename') 获取文件/目录信息 13 os.sep 输出操作系统特定的路径分隔符,win下为"\",Linux下为"/" 14 os.linesep 输出当前平台使用的行终止符,win下为" ",Linux下为" " 15 os.pathsep 输出用于分割文件路径的字符串 16 os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix' 17 os.system("bash command") 运行shell命令,直接显示 18 os.environ 获取系统环境变量 19 os.path.abspath(path) 返回path规范化的绝对路径 20 os.path.split(path) 将path分割成目录和文件名二元组返回 21 os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素 22 os.path.basename(path) 返回path最后的文件名。如何path以/或结尾,那么就会返回空值。即os.path.split(path)的第二个元素 23 os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False 24 os.path.isabs(path) 如果path是绝对路径,返回True 25 os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False 26 os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False 27 os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略 28 os.path.getatime(path) 返回path所指向的文件或者目录的最后存取时间 29 os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间
sys模块

1 sys.argv 命令行参数List,第一个元素是程序本身路径 2 sys.exit(n) 退出程序,正常退出时exit(0) 3 sys.version 获取Python解释程序的版本信息 4 sys.maxint 最大的Int值 5 sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值 6 sys.platform 返回操作系统平台名称