闭包和装饰器

闭包

一个函数套着另一个函数,内部函数又用到外部函数的变量 ,Python中,闭包的主要用途就是用于装饰器的实现

参考博文:https://blog.csdn.net/u013380694/article/details/90019571?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase

1、概念
闭包函数:声明在一个函数中的函数,叫做闭包函数。

闭包:内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。

2、特点
  让外部访问函数内部变量成为可能;

  局部变量会常驻在内存中;

  可以避免使用全局变量,防止全局变量污染;

  会造成内存泄漏(有一块内存空间被长期占用,而不被释放)

return xxx 是返回定位

return xxx() 是调用

#coding:utf-8

# y = kx + b

# 第一种
k = 1
b = 2
x = 4
print (k*x + b)

print('-'*50 + '第一种')

# 第二种
def line_2(k, x, b):
    print(k*x + b)

line_2(1,2,0)
line_2(2,3,0)
line_2(3,2,0)
#  缺点,多次计算这条线上的y值,每次都需要传递k, x, b的值,麻烦

print('-'*50 + '第二种')

# 第三种:全局变量
k = 1
b = 2
def line_3(x):
    print(k*x + b)

line_3(1)
line_3(2)
line_3(3)

k = 11
b = 33
line_3(1)
line_3(2)
line_3(3)
#  缺点:如果计算多条线上的y值,需要对全局变量进行修改,代码量增多,麻烦

print('-'*50 + '第三种')

# 第四种:缺省参数
def line_4(x, k=1, b=2):
    print(k*x + b)

line_4(1)
line_4(2)
line_4(3)

line_4(1, k=2, b=3)
line_4(2, k=2, b=3)
line_4(3, k=2, b=3)

# 优点:比全局变量方式好,k,b是函数line_4的一部分,而不是全局变量,因为全局变量可以任意的被其他函数修改
# 缺点:如果计算多条线上的y值,需要对关键字参数进行修改,代码量增多,麻烦

print('-'*50 + '第四种')
# 第五种:实例对象
class Line5(object):
    def __init__(self, k, b):
        self.k = k
        self.b = b
    def __call__(self, x):
        print(self.k*x + self.b)

line_5_1 = Line5(1, 2)  # 创建对象1
# 对象.方法()
# 对象()  __call__
line_5_1(0)
line_5_1(1)
line_5_1(2)
line_5_2 = Line5(11, 22)  # 创建对象2
line_5_2(0)
line_5_2(1)
line_5_2(2)

# 缺点:为了计算多条线上的y值,所有需要保存多个k,b的值,因此用了很多的实例对象,浪费资源

print('-'*50 + '第五种')


# 第六种:闭包
def line_6(k, b):
    def create_y(x):
        print(k*x + b)
    return create_y

line_6_1 = line_6(1, 2)
line_6_1(0)
line_6_1(1)
line_6_1(2)
line_6_2 = line_6(11, 22)
line_6_2(0)
line_6_2(1)
line_6_2(2)

print('-'*50 + '第六种')

 闭包和装饰器_第1张图片

 

装饰器 

函数名仅仅是个变量名,只不过指向了定义函数而已,要么整体之前要么整体之后控制

通用装饰器:①*args,**kwargs  ②拆包  ③return

def foo():
    print('foo普通函数')

# foo 表示是函数
foo()  # 表示执行foo函数


print('*'*50)

def foo():
    print('foo匿名函数')

foo = lambda  x: x + 1

foo(1)  # 执行lambda表达式,而不再是原来的foo函数,因为foo这个名字被重新指向了另一个匿名函数

代码规范:开放、封闭

def set_func(func):
    def call_func():
        print('----这是权限验证1----')
        print('----这是权限验证2----')
        func()
    return call_func

@set_func  # 添加装饰器,优先执行
def test1():
    print('----test1----')

test1()

原理: 把一个函数的引用,当成实参传到另一个闭包里面func,在闭包外面的变量,什么时候调用闭包里面的函数什么时候就去调这个引用

def set_func(func):
    def call_func():
        print('----这是权限验证1----')
        print('----这是权限验证2----')
        func()  # 执行test1函数
    return call_func

# @set_func  # 添加装饰器,优先执行
def test1():
    print('----test1----')

test1 = set_func(test1)  # 第二个test1是func()指向了test1函数
test1()

#test1()

demo:统计调用函数时长

import time

def set_func(func):
    def call_func():
        start_time = time.time()
        func()  # 执行test1函数
        stop_time = time.time()
        print('alltimeis %f' % (stop_time -start_time))
    return call_func

@set_func  # 添加装饰器,优先执行
def test1():
    print('----test1----')
    for i in range(100000):
        pass

test1()

对有参数num无返回值的函数进行装饰

import time

def set_func(func):  # func = 传整个函数
    print('----开始进行装饰----')
    def call_func(num):
        print('----这是权限验证1----')
        print('----这是权限验证2----')
        func(num)  # 执行test1函数
    return call_func


@set_func  # 添加装饰器,优先执行,相当于test1 = set_func(test1)
def test1(num):
    print('----test1----%s' % num)


@set_func  # 添加装饰器,优先执行,相当于test2 = set_func(test2)
def test2(num):
    print('----test2----%s' % num)


# test1 = set_func(test1)  等于装饰器效果
test1(100)
test2(200)

对不定长函数参数进行装饰

def set_func(func):  # func = 传整个函数
    def call_func(*args, **kwargs):  # * 表示可以保存多个
        print('----这是权限验证1----')
        print('----这是权限验证2----')
        # func(args, kwargs) 不行,相当于传递了2个参数:1个元组,1个字典
        func(*args, **kwargs)  # args:表示元组  *args:表示拆包(*对元组拆,**对字典拆)
    return call_func


@set_func  # 添加装饰器,优先执行,相当于test1 = set_func(test1)
def test1(num, *args, **kwargs):  #*args:参数打包成tuple给函数体调用 **kwargs 打包关键字参数成dict给函数体调用
    print('----test1----%d' % num)
    print('----test1----', args)   # 元组,分别打印
    print('----test1----', kwargs)   # 元组,分别打印


# test1 = set_func(test1)  等于装饰器效果
test1(100)
test1(100, 200)
test1(100, 200, 300, mm=200)

----这是权限验证1----
----这是权限验证2----
----test1----100
----test1---- ()
----test1---- {}
----这是权限验证1----
----这是权限验证2----
----test1----100
----test1---- (200,)
----test1---- {}
----这是权限验证1----
----这是权限验证2----
----test1----100
----test1---- (200, 300)
----test1---- {'mm': 200}

对有返回值的参数进行装饰:通用装饰器

def set_func(func):  # func = 传整个函数
    def call_func(*args, **kwargs):  # * 表示可以保存多个
        print('----这是权限验证1----')
        print('----这是权限验证2----')
        # func(args, kwargs) 不行,相当于传递了2个参数:1个元组,1个字典
        return func(*args, **kwargs)  # 返回值接收
    return call_func  # 返回位置


@set_func  # 添加装饰器,优先执行,相当于test1 = set_func(test1)
def test1(num, *args, **kwargs):  #*args:参数打包成tuple给函数体调用 **kwargs 打包关键字参数成dict给函数体调用
    print('----test1----%d' % num)
    print('----test1----', args)   # 元组,分别打印
    print('----test1----', kwargs)   # 元组,分别打印
    return 'ok'  # 返回值


# test1 = set_func(test1)  等于装饰器效果
ret = test1(100)
print(ret)

多个装饰器对一个函数:装饰器执行顺序从下往上

def add_grant(func):  # func = 传整个函数
    print('----装饰器1----开始grant----')
    def call_func(*args, **kwargs):
        print('----这是权限验证1----')
        return func(*args, **kwargs)  # 拆包
    return call_func


def add_select(func):  # func = 传整个函数
    print('----装饰器2----开始select----')
    def call_func(*args, **kwargs):
        print('----这是开始选择2----')
        return func(*args, **kwargs)  # 拆包
    return call_func


@add_grant  # 装饰器下面没有函数,不执行闭包里面的函数
@add_select
def test1():
    print('----test1----')


test1()

----装饰器2----开始select----
----装饰器1----开始grant----
----这是权限验证1----
----这是开始选择2----
----test1----

def set_func_2(func):
    def call_func():
        return '' + func() + ''
    return call_func


def set_func_1(func):
    def call_func():
        return '

' + func() + '

' return call_func @set_func_1 @set_func_2 def get_str(): return 'hahaha' print(get_str())

类装饰器

class Test(object):
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print('这里是装饰器添加的功能....')
        return self.func()


@Test  # get_str = Test(get_str)
def get_str():
    return 'hahaha'

print(get_str())

带参数的装饰器

def set_level(level_num):
    def set_func(func):
        def call_func(*args, **kwargs):
            if level_num == 10:
                print('----权限级别10,验证----')
            elif level_num == 2:
                print('----权限级别2,验证----')
            return func()
        return call_func
    return set_func

# ①.调用set_level并且将1当做实参传递
# ②.用①的返回值当做装饰器对test1函数进行装饰
@set_level(10)  # 带参数的装饰器
def test1():
    print('----test1----')
    return 'ok'

@set_level(2)
def test2():
    print('----test2----')
    return 'ok'

test1()
test2()

----权限级别10,验证----
----test1----
----权限级别2,验证----
----test2----
 

你可能感兴趣的:(Pyhon高级)