@@@文章内容参照老男孩教育 Alex金角大王,武Sir银角大王@@@
函数即对象
在python中,函数和我们之前的[1,2,3],‘abc‘,8 等一样都是对象,而且函数是最高级的对象(对象是类的实例化,可以调用相应的方法,函数是包含变量对象的对象。)
高阶函数
嵌套函数及闭包
1 def func(): 2 x = 1 3 def foo(): 4 print(x) 5 return foo 6 7 a = func() 8 a()
闭包(closure)是函数式编程的重要的语法结构
定义:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包
如上实例,foo就是内部函数,foo里引用了外部作用域的变量x(x在外部作用域func里面,不是在全局作用域),则这个内部函数foo就是一个闭包。
代码的开放封闭原则
软件开发中的一个原则“开放-封闭”原则,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:
- 封闭:已实现的功能代码块不应该被修改
- 开放:对现有功能的扩展开发
装饰器概念
装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等应用场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
1 import time 2 # 业务生产中大量调用的函数 3 def foo(): 4 print(‘hello foo‘) 5 foo() 6 # 现在有一个新的需求,希望可以记录下函数的执行时间,于是在代码中添加日志代码 7 def foo(): 8 start_time = time.time() 9 time.sleep(2) 10 print(‘hello foo‘) 11 stop_time =time.time() 12 print(‘spend %s‘ %(stop_time - start_time)) 13 14 foo() 15 16 # bar()、bar2()也有类似的需求,怎么做?再在bar函数里调用时间函数? 17 # 这样就造成大量雷同的代码,为了减少重复写代码,我们可以这样做,重新定义一个函数:专门设定时间 18 def show_time(func): 19 start_time = time.time() 20 func() 21 stop_time = time.time() 22 print(‘spend %s‘ %(stop_time - start_time)) 23 24 def foo(): 25 time.sleep(2) 26 print(‘hello foo‘) 27 28 show_time(foo)
逻辑上不难理解,而且运行正常。但是这样改变了调用方式,容易被人投诉,因为我们每次都要将一个函数作为参数传递给show_time函数。而且这种方式已经破坏了原有的代码逻辑结构,之前执行业务逻辑进,执行foo(),但是现在不得不改成show_time(foo)。那么有没有更好的方式呢?当然有,答案就 是装饰器。
简单装饰器
1 import time 2 def show_time(func): 3 def wrapper(): 4 start_time = time.time() 5 func() 6 stop_time = time.time() 7 print(‘spend %s‘ %(stop_time - start_time)) 8 9 return wrapper 10 11 # @符号是装饰器的语法堂,在定义函数的时候使用,避免再一次赋值操作 12 @show_time # foo = show_time(foo) 13 def foo(): 14 time.sleep(2) 15 print(‘hello foo‘) 16 17 foo()
装饰器在python使用如此方便都要归因于python函数能像普通的对象一样能作为参数传递给其他函数,可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。
带参数的被装饰函数
1 import time 2 def show_time(func): 3 def wrapper(a,b): 4 start_time = time.time() 5 ret = func(a,b) 6 stop_time = time.time() 7 print(‘spend %s‘ %(stop_time - start_time)) 8 return ret 9 10 return wrapper 11 12 @show_time 13 def add1(a,b): 14 time.sleep(1) 15 print(a + b) 16 17 add1(4,5) 18 19 # 注意函数的返回值时 20 @show_time 21 def add2(a,b): 22 time.sleep(1) 23 return a + b 24 25 print(add2(4,5))
不定长参数
1 import time 2 def show_time(func): 3 def wrapper(*args,**kwargs): 4 start_time = time.time() 5 ret = func(*args,**kwargs) 6 stop_time = time.time() 7 print(‘spend %s‘ %(stop_time - start_time)) 8 return ret 9 10 return wrapper 11 12 @show_time 13 def add(*args,**kwargs): 14 time.sleep(1) 15 sum = 0 16 for i in args: 17 sum += i 18 print(sum) 19 20 add(4,5,6,7,8,9)
带参数的装饰器
装饰器还有更大的灵活性,例如带参数的装饰器;在上面的装饰器调用中,比如@show_time,该装饰器唯一的参数就是执行业务的函数。装饰器的语法允许我们在调用时,提供其它参数,比如@auth(a)。这样就为装饰器的编写和使用提供了更大的灵活性。
1 user,passwd = ‘abc‘,‘abc123‘ # 存用户信息 2 user_status = False # 用户登录了就把这个改成True 3 4 def auth(auth_ytpe=0): # 把要执行的模块从这里传进来 5 def wrapper(func): 6 def inner(*args,**kwargs): # 7 if auth_ytpe == ‘1‘: 8 global user_status 9 if user_status == False: 10 username = input(‘Username:‘).strip() 11 password = input(‘Password:‘).strip() 12 if username == user and password == passwd: # 用户认证 13 print(‘welcome login ......‘) 14 user_status = True # 登入成功改成True 15 else: 16 print(‘wrong username or password!‘) 17 if user_status == True: 18 return func(*args,**kwargs) # 验证通过,调用相应功能函数 19 elif auth_ytpe == ‘2‘: 20 pass 21 return inner 22 return wrapper 23 24 @auth(0) 25 def index(): 26 print(‘welcome to index‘) 27 28 @auth(‘1‘) 29 def home(a): 30 print(‘welcome to home %s‘%(a)) 31 return home 32 33 @auth(‘2‘) 34 def bbs(): 35 print(‘welcome to bbs‘) 36 37 index() 38 print(home(‘33‘)) 39 bbs()
多层装饰器
1 def w1(fnuc): 2 def wrapper(): 3 return ‘<b>‘ + fnuc() + ‘</b>‘ 4 5 return wrapper 6 7 def w2(fnuc): 8 def wrapper(): 9 return ‘<i>‘ + fnuc() + ‘</i>‘ 10 11 return wrapper 12 13 @w1 14 @w2 15 def hello(): 16 return ‘hello‘ 17 18 print(hello())