Python 闭包与装饰器

原创
2020/04/18 21:34
阅读数 90

一、变量的作用域链

# -*- coding:utf-8 -*-

a = 10
def func1():
    b = 20
    def func2():
        c = 30
        return a + b + c
    return func2()


print(func1())

二、利用闭包突破作用域链

# -*- coding:utf-8 -*-


'''闭包
概念:在函数体重定义内部函数,并且使用了外部函数的变量,然后把内部函数给,那么这个内部函数就是闭包

优点:避免污染全局环境,这样就可以在函数体外使用函数体中定义的变量

缺点:数据长期驻留在内存中,造成内存极大的浪费。


'''
a = 10
def func1():
    b = 20
    def func2():
        c = 30
        return a
    return func2


f2 = func1()
print(f2())





def func3():
    b = 40
    def func4():
        return b
    return func4



三、装饰器概念

# -*- coding:utf-8 -*-

'''

是一个闭包,把一个函数作为参数然后返回一个替代版函数,本质上就是一个返回函数的函数

'''

#在不修改原函数的前提下增加函数的功能,最好的方式是使用装饰器
def func():
    print("Martin is a good man")


def f():
    print("***********")
    func()

四、简单装饰器

# -*- coding:utf-8 -*-

def func():
    print("sunck is a good man")

def wrapper(f):
    def inner():
        print("***********")
        f()
    return inner

# d = wrapper(func)
# d()
func = wrapper(func)
func()

五、复杂装饰器

# -*- coding:utf-8 -*-

# 下不修改say原函数代码的情况下增加say的功能,判断age是否符合常理
def say(name, age):
    return "%s is a good man! he is %d years old"%(name, age)



def wrapper(f):
    def inner(name, age):
        #增加功能
        if age <= 0:
            age = 0
        return f(name, age)
    return inner


say = wrapper(say)

print(say("Martin", -18))


六、使用@符号装饰

# -*- coding:utf-8 -*-
'''
python2.4支持使用@将装饰器应用在函数上,只需要再函数定义前加上@装饰器的名称即可

'''
def wrapper(f):
    def inner(name, age):
        #增加功能
        if age <= 0:
            age = 0
        return f(name, age)
    return inner

@wrapper
def say(name, age):
    return "%s is a good man! he is %d years old"%(name, age)

# 相当于  say = wrapper(say)

print(say("Martin", -18))


七、通用装饰器

# -*- coding:utf-8 -*-

def wrapper(f):
    def inner(*args, **kwargs):
        #在这增加功能
        print("no zuo no die")
        res = f(*args, **kwargs)
        #如果要修改原函数的返回值,在这修改
        return res
    return inner



@wrapper
def func(name, age):
    print(name, age)
    return "Martin is a good man"

print(func("kaige", 17))

@wrapper
def func2(height):
    print(height)
    print("**********")
func2(111)

八、参数的装饰器

# -*- coding:utf-8 -*-

def wrapper(count=3):
    def deco(f):
        def inner(*args, **kwargs):
            for i in range(count):
                f(*args, **kwargs)
        return inner
    return deco

@wrapper()
def func():
    print("Martin is a good man")

func()


九、计算程序运行时间

# -*- coding:utf-8 -*-
import time

def timer(f):
    def inner(*args, **kwargs):
        time1 = time.time()
        res = f()
        time2 = time.time()
        print("程序运行:%f"%(time2-time1))
        return res
    return inner

@timer
def func():
    print("Martin is a nice man")
    time.sleep(2)
    print("Martin is a good man")

func()

十、多个装饰器

# -*- coding:utf-8 -*-
def wrapper1(f):
    print("enter wrapper1")
    def inner1(*args, **kwargs):
        print("enter inner1")
        res = f(*args, **kwargs)
        print("exit inner1")
        return res
    print("exit wrapper1")
    return inner1

def wrapper2(f):
    print("enter wrapper2")
    def inner2(*args, **kwargs):
        print("enter inner2")
        res = f(*args, **kwargs)
        print("exit inner2")
        return res
    print("exit wrapper2")
    return inner2

def wrapper3(f):
    print("enter wrapper3")
    def inner3(*args, **kwargs):
        print("enter inner3")
        res = f(*args, **kwargs)
        print("exit inner3")
        return res
    print("exit wrapper3")
    return inner3

'''
装饰时:从距离近的装饰器开始装饰
执行时:从距离远的装饰器内部函数开始执行
'''
@wrapper1
@wrapper2
@wrapper3
def func(x, y):
    return x + y

print("----------------")
func(1, 2)



'''
inner3 = wrapper3(func)
inner2 = wrapper2(inner3)
inner1 = wrapper1(inner2)
func = inner1
'''

十一、装饰器使用场景

# -*- coding:utf-8 -*-

count = 0

'''
1、参数、结果检查
2、缓存
3、计数
4、日志
5、统计
6、权限管理
7、重试
'''

十二、计数函数执行次数

# -*- coding:utf-8 -*-

def count(f):
    index = 0
    def inner(*args, **kwargs):
        nonlocal index
        index += 1
        res = f(*args, **kwargs)
        print("第%d次执行"%index)
        return res
    return inner

@count
def func():
    print("Martin is a good man")


@count
def func1():
    print("Martin is a nice man")

func()
func()
func1()
func()
func1()

十三、retry装饰器

# -*- coding:utf-8 -*-

def retry(count=3, wait=0,exceptions=(Exception,)):
    import time
    def wrapper(f):
        def inner(*args, **kwargs):
            for i in range(count):
                try:
                    print("-------------------")
                    res = f(*args, **kwargs)
                except exceptions as e:
                    time.sleep(wait)
                    continue
                else:
                    return res
        return inner
    return wrapper

import random

@retry(5)
def connetSQL(ip, port, dbName, passwd):
    num = random.choice([1,2,3,4])
    print("**************", num)
    if num <= 4:
        10 / 0

connetSQL("", "", "", "")

————————————————
版权声明:本文为【PythonJsGo】博主的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
博主主页:https://my.oschina.net/u/3375733

本篇文章同步在个人公众号:

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部