闭包函数,装饰器

闭包函数

什么是闭包

闭包:闭是封闭(函数内部函数),包是包含(该内部函数对外部作用域而非全局作用域的变量的引用)。闭包指的是:函数内部函数对外部作用域而非全局作用域的引用。

两种为函数传值的方式

为函数传参的方式一:使用参数的形式

def func(x):
    print(x)

func(1)

为函数传参的方式二:包给函数

def outter(x):

    def inner():
        print(x)
    return inner

f = outter(1)
f()
f()
f()
# 查看闭包的元素
print(F"f.__closure__[0].cell_contents: {f.__closure__[0].cell_contents}")

闭包函数的应用

闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域。

应用领域:延迟计算(原来我们是传参,现在我们是包起来)、爬虫领域。

import requests

def outter(url):
    def get():
        response = requests.get(url)
        print(f"done: {url}")
    return get

baidu=outter('https://www.baidu.com')
python = outter('https://www.python.org')

baidu()
baidu()

python()
python()

装饰器

无参装饰器

什么是装饰器

器指的是工具,而程序中的函数就是具备某一功能的工具,所以装饰器指的是为被装饰器对象添加额外功能。因此定义装饰器就是定义一个函数,只不过该函数的功能是用来为其他函数添加额外的功能。

需要注意的是:

  • 装饰器本身其实是可以任意可调用的对象
  • 被装饰的对象也可以是任意可调用的对象

为什么用装饰器

如果我们已经上线了一个项目,我们需要修改某一个方法,但是我们不想修改方法的使用方法,这个时候可以使用装饰器。因为软件的维护应该遵循开放封闭原则,即软件一旦上线运行后,软件的维护对修改源代码是封闭的,对扩展功能指的是开放的。

装饰器的实现必须遵循两大原则:

  1. 不修改被装饰对象的源代码
  2. 不修改被装饰对象的调用方式

装饰器其实就是在遵循以上两个原则的前提下为被装饰对象添加新功能。

import time

def index():
    print('welcome to index')
    time.sleep(1)

def time_count(func):
    # func = 最原始的index
    def wrapper():
        start = time.time()
        func()
        end = time.time()
        print(f"{func} time is {start-end}")
    return wrapper

# f = time_count(index)
# f()

index = time_count(index)  # index为被装饰函数的内存地址,即index = wrapper
index()  # wrapper()
welcome to index
<function index at 0x102977730> time is -1.0038220882415771

完善装饰器

上述的装饰器,最后调用index()的时候,其实是在调用wrapper(),因此如果原始的index()有返回值的时候,wrapper()函数的返回值应该和index()的返回值相同,也就是说,我们需要同步原始的index()和wrapper()方法的返回值。

import time

def index():
    print('welcome to index')
    time.sleep(1)

    return 123

def time_count(func):
    # func = 最原始的index
    def wrapper():
        start = time.time()
        res = func()
        end = time.time()
        print(f"{func} time is {start-end}")

        return res
    return wrapper

index = time_count(index)
res = index()
print(f"res: {res}")
welcome to index
<function index at 0x102977620> time is -1.0050289630889893
res: 123

如果原始的index()方法需要传参,那么我们之前的装饰器是无法实现该功能的,由于有wrapper()=index(),所以给wrapper()方法传参即可。

import time

def index():
    print('welcome to index')
    time.sleep(1)

    return 123

def home(name):
    print(f"welcome {name} to home page")
    time.sleep(1)

    return name

def time_count(func):
    # func = 最原始的index
    def wrapper(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        end = time.time()
        print(f"{func} time is {start-end}")

        return res
    return wrapper

home = time_count(home)

res = home('egon')
print(f"res: {res}")

装饰器语法糖

在被装饰函数正上方,并且是单独一行写上@装饰器名

import time

def time_count(func):
    # func = 最原始的index
    def wrapper(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        end = time.time()
        print(f"{func} time is {start-end}")

        return res
    return wrapper

@time_count  # home = time_count(home)
def home(name):
    print(f"welcome {name} to home page")
    time.sleep(1)

    return name

@time_count  # index = time_count(index)
def index():
    print('welcome to index')
    time.sleep(1)

    return 123

res = home('egon')
print(f"res: {res}")
welcome egon to home page
<function home at 0x102977620> time is -1.0005171298980713
res: egon

装饰器模板

def deco(func):
    def wrapper(*args,**kwargs):
        res = func(*args,**kwargs)
        return res
    return wrapper

有参装饰器

无参装饰器只套了两层,本节将讲一个套三层的装饰器——有参装饰器,但现在我们先实现一个用户登录注册的装饰器。

import time

current_user = {'username': None}

def login(func):
    # func = 最原始的index
    def wrapper(*args, **kwargs):
        if current_user['username']:
            res = func(*args, **kwargs)

            return res

        user = input('username: ').strip()
        pwd = input('password: ').strip()

        if user == 'nick' and pwd == '123':
            print('login successful')
            current_uesr['usre'] = user
            res = func(*args, **kwargs)

            return res
        else:
            print('user or password error')

    return wrapper

@login
def home(name):
    print(f"welcome {name} to home page")
    time.sleep(1)

    return name

@login
def index():
    print('welcome to index')
    time.sleep(1)

    return 123

res = index()
username: nick
password: 123
login successful
welcome to index

对于上面的登录注册,我们把用户登录成功的信息写入内存当中。但是在工业上,用户信息可以存在文本中、mysql中、mongodb当中,但是我们只让用户信息来自于file的用户可以认证。因此我们可以改写上述的装饰器。

import time

current_user = {'username': None}

def login(func):
    # func = 最原始的index
    def wrapper(*args, **kwargs):

        if current_user['username']:
            res = func(*args, **kwargs)

            return res

        user = input('username: ').strip()
        pwd = input('password: ').strip()

        engine = 'file'

        if engine == 'file':
            print('base of file')
            if user == 'nick' and pwd == '123':
                print('login successful')
                current_uesr['usre'] = user
                res = func(*args, **kwargs)

                return res
            else:
                print('user or password error')
        elif engine == 'mysql':
            print('base of mysql')
        elif engine == 'mongodb':
            print('base of mongodb')
        else:
            print('default')

    return wrapper

@login
def home(name):
    print(f"welcome {name} to home page")
    time.sleep(1)

@login
def index():
    print('welcome to index')
    time.sleep(1)

res = index()
username: nick
password: 123
base of file
login successful
welcome to index

三层闭包

现在需求改了,我们需要判断用户动态的获取用户密码的方式,如果是file类型的,我们则让用户进行认证。因此我们可以使用有参装饰器。

import time

current_uesr = {'username': None}

def auth(engine='file'):

    def login(func):
        # func = 最原始的index
        def wrapper(*args, **kwargs):

            if current_user['username']:
                res = func(*args, **kwargs)

                return res

            user = input('username: ').strip()
            pwd = input('password: ').strip()

            if engine == 'file':
                print('base of file')
                if user == 'nick' and pwd == '123':
                    print('login successful')
                    current_uesr['usre'] = user
                    res = func(*args, **kwargs)

                    return res
                else:
                    print('user or password error')
            elif engine == 'mysql':
                print('base of mysql, please base of file')
            elif engine == 'mongodb':
                print('base of mongodb, please base of file')
            else:
                print('please base of file')

        return wrapper

    return login

@auth(engine='mysql')
def home(name):
    print(f"welcome {name} to home page")
    time.sleep(1)

@auth(engine='file')
def index():
    print('welcome to index')
    time.sleep(1)

res = index()
username: nick
password: 123
base of file
login successful
welcome to index

由于两层的装饰器,参数必须得固定位func,但是三层的装饰器解除了这个限制。我们不仅仅可以使用上述单个参数的三层装饰器,多个参数的只需要在三层装饰器中多加入几个参数即可。也就是说装饰器三层即可,多加一层反倒无用。

原文地址:https://www.cnblogs.com/zhoajiahao/p/10970111.html

时间: 2024-10-21 08:50:06

闭包函数,装饰器的相关文章

函数嵌套 ,名称空间与作用域 ,闭包函数 ,装饰器 ,迭代器, 生成器 三元表达式,列表解析,生成器表达式 递归与二分法, 内置函数

函数嵌套名称空间与作用域闭包函数装饰器迭代器生成器三元表达式,列表解析,生成器表达式递归与二分法内置函数--------------------------------------------函数的嵌套调用:在调用一个函数的过程中,又调用了其他函数函数的嵌套定义:在一个函数的内部,又定义另外一个函数def max(x,y): if x>y: return x else: return ydef max1(a,b,c,d): res=max(a,b) res2=max(res,c) res3=ma

Python 函数对象 命名空间与作用域 闭包函数 装饰器 迭代器 内置函数

一.函数对象 函数(Function)作为程序语言中不可或缺的一部分,但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性. 那到底什么是第一类对象(First-Class Object)呢? 在 Python 中万物皆为对象,函数也不例外,函数作为对象可以赋值给一个变量.可以作为元素添加到集合对象中.可作为参数值传递给其它函数,还可以当做函数的返回值,这些特性就是第一类对象所特有的. 1.函数身为一个对象,拥有对象模型的三个通用属性:id.类型.和值.

【Python 函数对象 命名空间与作用域 闭包函数 装饰器 迭代器 内置函数】

一.函数对象 函数(Function)作为程序语言中不可或缺的一部分,但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性. 那到底什么是第一类对象(First-Class Object)呢? 在 Python 中万物皆为对象,函数也不例外,函数作为对象可以赋值给一个变量.可以作为元素添加到集合对象中.可作为参数值传递给其它函数,还可以当做函数的返回值,这些特性就是第一类对象所特有的. 1.函数身为一个对象,拥有对象模型的三个通用属性:id.类型.和值.

闭包函数 装饰器 有参装饰器

闭包函数: 1 内部函数 2 包含对外部作用域而非全局作用域的引用闭包函数的特点: 自带作用域  延迟计算 #闭包函数定义 1 def timmer(func): 2 def inner(*args,**kwargs): 3 re = func(*args,**kwargs) 4 return re 5 return inner 6 7 index(): 8 print("hello") 9 10 index = timmer(index) #index == inner 11 ind

&lt;04day&gt;_函数嵌套--闭包函数--装饰器--迭代器--生成器

一.函数的嵌套定义 1.python函数支持嵌套 def f1(): #f1函数的定义 def f2(): #f2函数的定义 print('from f2') def f3(): #f3函数的定义 print('from f3') f2() f1() 嵌套函数--运行结果说明: 1首先调用f1()结果,f1函数为空.担保函f2函数,f2函数有内容打印并且有调用,f2函数包含f3函数,但f3函数无调用. 运行结果: 列子:多个数据之间的大小比较. #!/usr/bin/python # -*- c

day12.1_闭包函数+装饰器

一.闭包函数 闭包的定义:①该函数是一个内部函数 ②该函数包含对外部的作用域(非全局作用域)中名字的引用 1. 为函数体传值的方式 1.1 使用参数形式 1.2 包给函数 def outter(x): def inner(): print(x) return inner #函数当返回值(对象) f=outter(1) #相当于赋值 f() 二.装饰器 1.装饰器是什么? ①为被装饰器对象添加额外的功能  ② 可以当成工具,函数就具备某一功能的工具 装饰器本省可以是任意可调用的对象,被装饰的对象也

Python作用域--&gt;闭包函数--&gt;装饰器

1.作用域: 在python中,作用域分为两种:全局作用域和局部作用域. 全局作用域是定义在文件级别的变量,函数名.而局部作用域,则是定义函数内部. 关于作用域,我要理解两点:a.在全局不能访问到局部定义的变量 b.在局部能够访问到全局定义的变量,但是不能修改全局定义的变量(当然有方法可以修改) 下面我们来看看下面实例: x = 1 def funx(): x = 10 print(x) # 打印出10 funx() print(x) # 打印出1 如果局部没有定义变量x,那么函数内部会从内往外

闭包函数 装饰器

什么是闭包函数 闭:指的是闭包函数数定义在一个函数内部的函数 包:该内部函数包含对外城函数作用域名字的引用 需要结合函数对象的概念将闭包函数返回到全局作用域去使用,从而打破函数层级的限制 为什么要用闭包函数 闭包函数提供了一种为函数体传值的解决方案 如何用闭包函数 # 为函数体传值的方式一:参数 # def func(x,y): # print(x+y) # # func(1,2) 3 # 为函数体传值的方式二:闭包 def outter(x,y): # x=1 # y=2 def func()

python之闭包函数 装饰器 作业

一:编写函数,(函数执行的时间是随机的) import randomdef t(): time.sleep(random.randrange(1,3)) print('hello')二:编写装饰器,为函数加上统计时间的功能 import timeimport randomdef timebe(func): def wrapper(*args,**kwargs): start_time=time.time() res = func(*args, **kwargs) end_time=time.ti

函数进阶——闭包,装饰器,生成器,迭代器

闭包 函数定义和函数表达式位于另一个函数的函数体内(嵌套函数).而且,这些内部函数可以访问他们所在的外部函数中声明的所有局部变量.参数.当其中一个这样的内部函数在包含他们的外部函数之外被调用时,就会形成闭包. 装饰器 在不修改原函数的情况下,给原函数增加新的功能,使得程序变得可扩展 http://www.cnblogs.com/alex3714/articles/5765046.html(转) 列表生成式 1 a = [i+1 for i in range(10)] 2 print(a)#[1,