Python Day 11 + Python Day 12 函数(函数名的应用,闭包,装饰器)

Python Day 11+Python Day 12 函数(函数名的应用,闭包,装饰器)

函数名的本质和应用

  函数名本质上就是函数的内存地址。

    1.可以被引用

    2.可以被当作容器类型的元素

    3.可以当作函数的参数和返回值

    *不明白?那就记住一句话,就当普通变量用

  函数名的应用 具有以下几种特征也称为第一类对象

    1,直接打印函数名得到的是函数的内存地址 <function func1 at 0x0000000002876B70>   

def func1():
    print(666)
print(func1)
View Code

    2、函数名可以赋值运算。

def func1():
    print(666)
f1 = func1
f1()
View Code

    3、函数名可以作为函数的参数。

def func1():
    print(666)

def func2(x):
    x()
    print(555)
func2(func1)
View Code

    4、函数名可以作为容器类数据类型的元素。

def func1():
    print(666)

def func2():
    print(222)

def func3():
    print(111)

def func4():
    print(777)
l1 = [func1, func2, func3, func4]
for i in l1:
    i()
dic1 = {
    1:func1,
    2:func2,
    3:func3,
    4:func4,
}
dic1[1]()
View Code 

    5、函数名可以当做函数的返回值

def func1():
    print(666)

def func2(x):  # x = func1
    print(222)
    return x
ret = func2(func1)
ret()
View Code

 

闭包

  函数内部定义的函数称为内部函数

  内部函数包含对外部作用域而非全剧作用域变量的引用,该内部函数称为闭包函数

  内层函数对外层函数非全局变量的引用就叫闭包。


1、判断是不是闭包 函数名.__closure__

返回的None则不是闭包,返回的是cell.... 则是闭包

def func1():
    name = '老男孩'  
    def inner():   # 内部函数
        print(name)   #非全局变量引用,闭包
    inner()
    print(inner.__closure__)   (<cell at 0x000001D0C19C75B8: str object at 0x000001D0C1A637B0>,)
func1()
def func1():
    global name
    name = '老男孩'

    def inner():
        print(name)
    inner()
    print(inner.__closure__)  # None
func1()
View Code

 

2、闭包的作用。

  当执行一个函数时,如果解释器判断此函数内部闭包存在,Python机制,闭包的所在的临时名称空间不会随着函数的执行完毕而消失。


装饰器

  本质上就是一个python函数,他可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。

  装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景。 装饰器的本质是闭包

#装饰器的固定格式
def wrapper(f):
    def inner(*args,**kwargs):
        '''执行被装饰函数之前的操作'''
        ret = f(*args,**kwargs)
        """执行被装饰函数之后的操作"""
        return ret
    return inner
#装饰器的固定格式--wraps版  (可以查看函数信息)
from functools import wraps

def deco(func):
    @wraps(func) #加在最内层函数正上方
    def wrapper(*args,**kwargs):
        return func(*args,**kwargs)
    return wrapper

 

#带开关参数的装饰器
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()
带开关参数的装饰器

 

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

def wrapper1(func):
    def inner():
        print('wrapper1 ,before func')
        func()
        print('wrapper1 ,after func')
    return inner

def wrapper2(func):
    def inner():
        print('wrapper2 ,before func')
        func()
        print('wrapper2 ,after func')
    return inner

@wrapper2
@wrapper1
def f():
    print('in f')

f()
多个装饰器装饰同一个函数

 开放封闭原则。

  1.对扩展是开放的
    为什么要对扩展开放呢?
    我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。
  2.对修改是封闭的
    为什么要对修改封闭呢?
    就像我们刚刚提到的,因为我们写的一个函数,很有可能已经交付给其他人使用了,如果这个时候我们对其进行了修改,
    很有可能影响其他已经在使用该函数的用户。
装饰器完美的遵循了这个开放封闭原则。

装饰器的进化史

  前提:要求统计执行时间。

  存在问题:1、改变了函数的执行方式 2、没有返回值

import time
def my_print():
    time.sleep(0.3)
    print('欢迎')

=========================

def timmer(f):
    starttime = time.time()
    f()
    endtime = time.time()
    return print('程序执行时间:{}'.format(endtime-starttime))

timmer(my_print)

=========================
欢迎
程序执行时间:0.30084800720214844
原始

  前提:不能改变执行方式

  存在问题:1、此方法虽然解决执行方式的问题,但是由一行执行变成了3行执行,需要大量的精力去修改。2、没有返回值

import time
def my_print():
    time.sleep(0.3)
    print('欢迎')
=====================
def timmer(f):
    starttime = time.time()
    f()
    endtime = time.time()
    return print('程序执行时间:{}'.format(endtime-starttime))

f1 = my_print
my_print = timmer
my_print(f1)

=====================
欢迎
程序执行时间:0.30083727836608887
原始修改版

  前提:不能改变执行方式,无传参,无返回值

  存在问题:1、没有返回值

import time
def my_print():
    time.sleep(0.3)
    print('欢迎')

===================

def timmer(f):
    def inner():
        starttime = time.time()
        f()
        endtime = time.time()
        print('程序执行时间:{}'.format(endtime-starttime))
    return inner

my_print = timmer(my_print)
my_print()

===================
欢迎
程序执行时间:0.3008255958557129
初级装饰器
#语法糖  (装饰器需要放在功能函数上方)
import time
def timmer(f):
    def inner():
        starttime = time.time()
        f()
        endtime = time.time()
        print('程序执行时间:{}'.format(endtime-starttime))
    return inner

@timmer  #效果等同于 my_print = timmer(my_print)
def my_print():
    time.sleep(0.3)
    print('欢迎')

my_print()
初级装饰器+语法糖

  前提:不能改变执行方式,有传参

import time
def timmer(f):
    def inner(*args,**kwargs):
        starttime = time.time()
        '''函数执行前的操作'''
        f(*args,**kwargs)
        '''函数执行后的操作'''
        endtime = time.time()
        print('程序执行时间:{}'.format(endtime-starttime))
    return inner

@timmer
def my_calc(*args,operation='+',**kwargs):
    time.sleep(0.3)
    result = 0
    for i in args:
        if operation == '+':
            result += i
        elif  operation == '-':
            result -= i
        else:
            return "请输入运算方法(+、-),其他方法暂不支持。"
    return result

print(my_calc(1,2,3,4,operation='+'))
修改版装饰器(使用形参的动态参数接受传参,对数据传递给功能函数时进行聚合和打散)

  前提:不能改变执行方式,有传参,需要返回值

import time
def timmer(f):
    def inner(*args,**kwargs):
        starttime = time.time()
        '''函数执行前的操作'''
        ret = f(*args,**kwargs)
        '''函数执行后的操作'''
        endtime = time.time()
        print('程序执行时间:{}'.format(endtime-starttime))
        return ret
    return inner

================================

@timmer
def my_calc(*args,operation='+',**kwargs):
    time.sleep(0.3)
    result = 0
    for i in args:
        if operation == '+':
            result += i
        elif  operation == '-':
            result -= i
        else:
            return "请输入运算方法(+、-),其他方法暂不支持。"
    return result

print(my_calc(1,2,3,4,operation='+'))

================================
程序执行时间:0.30084824562072754
10
万能装饰器

  前提:不能改变执行方式,有传参,需要返回值,可以查看函数信息

  函数的有用信息

def index():
    '''这是一个主页信息'''
    print('from index')

print(index.__doc__)    #查看函数注释的方法
print(index.__name__)   #查看函数名的方法
如何查看函数信息

  

  引入 from functools import wraps 

  @wraps(func) #加在最内层函数正上方

import time
from functools import wraps

def timmer(func):
    @wraps(func)
    def inner(*args,**kwargs):
        starttime = time.time()
        '''函数执行前的操作'''
        ret = func(*args,**kwargs)
        '''函数执行后的操作'''
        endtime = time.time()
        print('程序执行时间:{}'.format(endtime-starttime))
        return ret
    return inner

@timmer
def my_calc(*args,operation='+',**kwargs):
    time.sleep(0.3)
    result = 0
    for i in args:
        if operation == '+':
            result += i
        elif  operation == '-':
            result -= i
        else:
            return "请输入运算方法(+、-),其他方法暂不支持。"
    return result

print(my_calc(1,2,3,4,operation='+'))
万能装饰器修改版

 

#带参数的装饰器
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()
带开关的万能装饰器

  @timer_out(flag)  # 1,步 timer_out(flag) == timer 2,@与timer结合,变成你熟悉的装饰器 @timer

 

def wrapper1(func):
    def inner():
        print('wrapper1 ,before func')
        func()
        print('wrapper1 ,after func')
    return inner

def wrapper2(func):
    def inner():
        print('wrapper2 ,before func')
        func()
        print('wrapper2 ,after func')
    return inner

@wrapper2
@wrapper1
def f():
    print('in f')

f()
多个装饰器装饰同一个函数
 1 def wrapper1(func):                     #6 func = func1(函数名)
 2     def inner1(*args,**kwargs):
 3         print('wrapper1 ,before func')  #8 功能函数执行前操作
 4         ret = func(*args,**kwargs)      #9 执行功能函数赋值给ret
 5         print('wrapper1 ,after func')   #10 功能函数执行后操作
 6         return ret                      #11 将执行功能函数结果返回给调用者 return inner1
 7     return inner1                       #7 调用inner1 ,将执行结果返回给wrapper1调用者 wrapper2中的func
 8 
 9 def wrapper2(func):                     #3 func = inner1
10     def inner2(*args,**kwargs):
11         print('wrapper2 ,before func')  #4 inner1函数执行前操作
12         ret = func(*args,**kwargs)      #5 执行inner1函数赋值给ret
13         print('wrapper2 ,after func')   #12 inner1函数执行后操作
14         return ret                      #13 将执行inner1结果返回给调用者 return inner2
15     return inner2                       #14 调用inner2 ,将执行结果返回给wrapper2调用者func1()
16 
17 @wrapper2                               #2 func1 = wrapper2(func1 此时的func1新变量 = inner1) 。 func1 = wrapper2(inner1)  func1(最新变量) = inner2 
18 @wrapper1                               #1 func1 = wrapper1(func1) 。 func1(新变量) = inner1
19 def func1():
20     print('in func1')
21 func1()
多个装饰器执行流程

  多个装饰器装饰同一函数执行过程:

 

 

posted @ 2018-05-11 17:11  eailoo  阅读(152)  评论(0编辑  收藏  举报