python - 闭包与装饰器

目录

一、python的闭包

示例1:闭包

示例2:形成闭包的条件

示例3:形成闭包以后,闭包函数会得到一个非空的__closure__属性

示例4:赋值引用闭包和直接调用外函数的区别

二、装饰器

示例1:统计函数执行时间

示例2:写一个统计函数运行时间的装饰器

示例3:什么是装饰器

示例4:用装饰器实现权限控制

示例5:保留元数据

示例6:用类实现装饰器

示例7:装饰类


一、python的闭包

示例1:闭包

def outer(x):
    a = 300

    def inner():
        print(f"两数之和{x + a}")
    return inner

d = outer(10)
d()

 变量解析原则:

        LEGB 原则

         local当前局部变量  enclosing function 闭包空间  global全局  buildins 内建模块
         理论上来说,函数执行完了以后,变量a会释放
         但是这个时候还有inner函数在引用他们,这个时候就形成了闭包

示例2:形成闭包的条件

形成闭包条件:(缺一不可)
1、必须有一个内嵌函数
2、内函数必须引用外函数的变量
3、外函数必须返回内函数

示例3:形成闭包以后,闭包函数会得到一个非空的__closure__属性

def outer(x):
    a = 300

    def inner():
        print(f"两数之和{x + a}")
    return inner


d = outer(10)
d()
# 闭包形成后,闭包函数会得到一个非空的__closure__属性
print(dir(d))
print(d.__closure__)


E:\python\python3.9.1\python.exe E:/tlbb/2022-07-29-闭包和装饰器/01、闭包.py
两数之和310
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
(<cell at 0x0000015CD0A9FE80: int object at 0x0000015CD09993B0>, <cell at 0x0000015CD09417F0: int object at 0x0000015CBEE46A50>)

Process finished with exit code 0

示例4:赋值引用闭包和直接调用外函数的区别

虽然代码一样,但是每次调用外函数都会重新执行,创建一个新的tmp_list和inner
匿名变量,都是统一放到匿名空间的,所以地址一样

tmp_list = []
def outer():
    tmp_list = []

    def inner(name):
        tmp_list.append(1)
        print(f"{name} -- {tmp_list}")
    return inner


d1 = outer()
d2 = outer()
d1("d1")
d2("d2")
# 虽然代码一样,但是每次调用外函数都会重新执行,创建一个新的tmp_list和inner
print(id(d1), id(d2))
# 匿名变量,都是统一放到匿名空间的,所以地址一样
print(id(outer()), id(outer()))

E:\python\python3.9.1\python.exe E:/tlbb/2022-07-29-闭包和装饰器/01、闭包.py
d1 -- [1]
d2 -- [1]
2138501753296 2138501753440
2138501753584 2138501753584

二、装饰器

示例1:统计函数执行时间

时间戳:

        从1970年1月1日的0点0分0秒到现在所经历的秒数

import time


def func1():
    time.sleep(2)
    print("func1....")


# 时间戳
# 从1970年1月1日的0点0分0秒到现在所经历的秒数
t1 = time.time()
func1()
t2 = time.time()
print(f"函数执行时间{t2 - t1}")

E:\python\python3.9.1\python.exe E:/tlbb/2022-07-29-闭包和装饰器/02、装饰器.py
func1....
函数执行时间2.0112464427948

示例2:写一个统计函数运行时间的装饰器

@ :修饰符

import time


def runtime(func):
    print("this is runtime")
    def inner():
        start = time.time()
        func()
        end = time.time()
        print(f"函数执行花了{end - start}s")
    return inner


@runtime  # @修饰符去使用装饰器 # runtime(func2)
def func2():
    time.sleep(2)
    print("func2....")


E:\python\python3.9.1\python.exe E:/tlbb/2022-07-29-闭包和装饰器/02、装饰器.py
this is runtime
func2....
函数执行花了2.0134215354919434s

示例3:什么是装饰器

装饰器是一种模式,它的本质是闭包,
他在不改变函数或者类的源代码的基础上
为函数或类添加功能
 装饰器有什么用 
• 你可以考虑在装饰器中置入通用功能的代码来降低程序复杂度。例如,可以用装饰器来:
 • 引入日志
 • 增加计时逻辑来检测性能
 • 给函数加入事务的能力
 • 权限控制

示例4:用装饰器实现权限控制

# 装饰器实现权限控制
def login_required(func):
    def inner(*args, **kwargs):
        if username == "root":
            print("欢迎")
            result = func(*args, **kwargs)
            return result
        else:
            return "权限不够"
    return inner


# 可以应用多个装饰器,但是要注意顺序
# 从最上面的装饰器的内涵式开始执行
@login_required
def add(a, b):
    time.sleep(2)
    return a + b


username = input("请输入用户名:")
result = add(1, 2)
print(result)

E:\python\python3.9.1\python.exe E:/tlbb/2022-07-29-闭包和装饰器/02、装饰器.py
请输入用户名:root
欢迎
3

示例5:保留元数据

import time


def runtime(func):
    # 保留传递进来的函数的元数据,将它的元数据赋值给inner
    @functools.wraps(func)
    def inner(*args, **kwargs):  # 让装饰器更加通用
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"函数  {func.__name__}  执行花了:{end -start}s")
        return result
    return inner
#
# a = runtime("name")
# add = a(add)


@runtime  # add = runtime(add)
def add(a, b):
    print("this is add ")
    time.sleep(1)
    return a+b

add(1, 2)

E:\python\python3.9.1\python.exe E:/tlbb/2022-07-29-闭包和装饰器/03、装饰器参数.py
this is add 
函数  add  执行花了:1.0147972106933594s
import functools
import time
def deco(name):
    def runtime(func):
        #保留传递进来的函数的元数据,将它的元数据赋值给inner
        @functools.wraps(func)
        def inner(*args, **kwargs):  #让装饰器更加通用
            start = time.time()
            result = func(*args, **kwargs)
            end = time.time()
            print(f"函数执行花了{end -start}s")
            print(f"name is {name}")
            return result
        return inner
    return runtime
# runtime = deco(name="sanle")
#func1 = runtime(func1)
@deco(name="sanle")
def func1():
    time.sleep(3)
    print("this is func1")
func1()

示例6:用类实现装饰器

import time
class A:
    def __init__(self, func):
        self.func = func

    def __call__(self, func):
        def deco(*args, **kwargs):
            start = time.time()
            print("this is call")
            result = func(*args, **kwargs)
            end = time.time()
            print(f"函数执行时间{end - start}")
            return result
        return deco

@A("name")
def func1():
    time.sleep(2)
    print("i am func1....")


func1()

示例7:装饰类

def outer(cls):
    def inner(*args, **kwargs):
        print(f"class name is:{cls.__name__}")
        return cls(*args, **kwargs)
    return inner


@outer
class A:
    def __init__(self, name):
        self.name = name


print(type(A))
m = A("sc")
print(m.name)


E:\python\python3.9.1\python.exe E:/tlbb/2022-07-29-闭包和装饰器/05、装饰类.py
<class 'function'>
class name is:A
sc

猜你喜欢

转载自blog.csdn.net/qq_48391148/article/details/126063851