0
点赞
收藏
分享

微信扫一扫

三十四、Python--闭包与装饰器

古月无语 2022-03-22 阅读 70
python

目录

1.闭包

        1.1什么是闭包

        1.2形成闭包的三个条件

        1.3一个简单的闭包函数

        1.4__closure__属性

        1.5闭包原理深入

        1.6闭包的意义

2.装饰器

        2.1什么是装饰器

        2.2装饰器初体验

        2.3装饰器进阶

        2.4保留原数据

        2.5装饰器传参

        2.6属性包装装饰器

        2.7用类实现装饰器

        2.8装饰类


1.闭包

        1.1什么是闭包

        在函数中可以(嵌套)定义另一个函数时,如果内部函数引用了外部函数的变量,则可能产生闭包。

        闭包可以用来在一个函数与一组私有变量之间创建关联关系。

        在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。

        1.2形成闭包的三个条件

        必须有一个内嵌函数

        内部函数必须引用外部函数的变量

        外部函数必须返回内函数

        1.3一个简单的闭包函数

        1.3.1创建

def outer():
    tmp_list=[]
    def inner(name):
        tmp_list.append(1)
        print(name,tmp_list)
    return inner

# 外函数为outer,返回值是内部函数inner,inner为内函数,引用了外函数变量tmp_list

          1.3.2调用闭包函数

         #调用函数outer将返回值赋给d1,d1现在闭包函数中的inner,可以调用inner函数。

        1.3.3再次调用闭包函数

        #每次调用外函数,都会重新执行,创建一个新的tmp_list和inner 

        1.4__closure__属性

        # 形成闭包之后,闭包函数会得到一个非空属性__closure__属性

        1.5闭包原理深入

def outer():
    fs = []
    for i in range(5):
        def inner():
            return i * i
        fs.append(inner)
    return fs
f1, f2, f3, f4, f5 = outer()
# 执行完outer后, 将inner添加到了fs中
print(f1())
# 调用inner(),i=4,所以返回值是16

         #不明白可以去debug调试中看下看执行过程。

        1.6闭包的意义

        # 闭包不是必须的
        # 闭包只是提供了一种方案

2.装饰器

        2.1什么是装饰器

        装饰器时一种设计模式,在不改变原代码的基础上,添加额外功能。

        本质上一种闭包函数

        把函数当做参数传递的闭包就是装饰器

        2.2装饰器初体验

import time
def runtime(func):
    def inner():
        start = time.time()
        func()
        end = time.time()
        rt = end -start
        return rt
    return inner
@runtime #-->func1 = runtime(func1)
def func1():
    time.sleep(1)
    print(f"func1...")
@runtime
def func2():
    time.sleep(2)
    print(f"func2...")
inner1 = runtime(func1)
print(inner1())
inner2 = runtime(func2)
print(inner2())

        输出如下

        2.3装饰器进阶

        一个函数可以同时用两个装饰器来装饰

user = {"root": "123456", "admin": "admin"}
name = input("请输入用户名:")
passwd = input("请输入密码:")
def login(func):
    def inner1(*args, **kwargs):
        if name in user.keys():
            if user.get(name, 0) == passwd:
                print(f"{name}登录成功")
                result = func(*args, **kwargs)
                return result
            else:
                print("密码错误")
        else:
            print("账户错误")
    return inner1
def identify(func):
    def inner2(*args, **kwargs):
        if name == "root":
            print("root权限")
            print(func(*args, **kwargs))

        else:
            print("没有权限")
        result = func(*args, **kwargs)
        return result
    return inner2
@login
@identify
def add(a, b):
    return a+b

add(1, 2)

        2.4保留原数据

        add函数经装饰器装饰后返回的不是add,而是inner。

        如果我们要获取add以及文档注释,该怎么做呢?

        2.5装饰器传参

        需要使用三层函数封装

        #自身不需要传入参数,只需要两层函数封装

        #自身需要传入参数,需要三层函数封装

        如何实现两种功能继承于同一个装饰器呢?

import time
import functools
def deco(d = None, username = None):
    def cost(func):
        # 把func的元数据复制给inner
        @functools.wraps(func)
        def _cost(*args, **kwargs):
            print(f"装饰器带参数:{username}")
            start = time.time()
            func()
            end = time.time()
            rt = end -start
            return rt
        return _cost
    if d:
        return cost(d)
    else:
        return cost

# @deco(username="sc")
# @deco()
@deco
def add():
    print("this is add")

add()

带参数实现

​​​​​​​

不带参数实现

        2.6属性包装装饰器

# @property 把方法当做属性来使用
# 设定Person属性age,可以修改age,当age范围不在0到100之间报错
class Person():
    _age = 1
    # age = 100
    @property
    #本身会创建另外两个装饰器 @age.setter @age.deleter
    def age(self):
        return self._age
    @age.setter
    def age(self, _age):
        if 0< _age < 100:
            self._age = _age
        else:
            raise ValueError("年龄不在范围内")

p = Person()
print(p.age)
p.age = 100

        2.7用类实现装饰器

        原理: 让类实现__call__函数,并返回一个函数

# 用类实现带参数的装饰器
# class A():
#     def __init__(self, username):
#         self.username = username
#
#     def __call__(self, func):
#         def deco(*args, **kwargs):
#             func(*args, **kwargs)
#         return deco
# @A("sc")
# def func1():
#     print("I am func1")
#
# func1()

# 用类实现不带参数的装饰器
import time
class A():
    def __init__(self,func):
        self.func = func

    def __call__(self, *args, **kwargs):
        start = time.time()
        result = self.func(*args, **kwargs)
        end = time.time()
        print(f"花费了{end-start}s")
        return result
# 将func1作为参数传入类A,实例化出来一个对象func1
@A  #func1 = A(func1)
def func1():
    time.sleep(1)
#调用func1的__call__方法
func1()

        2.8装饰类

def outer(cls):
    def inner(*args, **kwargs):
        print(f"class name is {cls.__name__}")
        return cls(*args, **kwargs)
        pass
    return inner
# 将类A作为参数传入函数outer,返回inner
# 实例化m和m2,执行inner,返回一个实例化对象
@outer  #--> A = outer(A)
class A:
    def __init__(self, name):
        self.name = name
print(type(A))
# 装饰器将A变为了一个函数inner
m = A("sc")
m2 = A("sc2")
print(m.name)
print(m2.name)
举报

相关推荐

0 条评论