闭包函数与装饰器

闭包函数

什么是闭包

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

def outter():
    x = 1

    def inner():
        print(x)  # x = 1
    return inner


f = outter()  # f = inner


def f2():
    x = 2
    f()  # f() = inner()


f2()
1

两种为函数传参的方式

方式一:使用参数的形式

def func(x):
    print(x)


func(1)
1

方式二:包给函数

def outter(x):

    def inner():
        print(x)
    return inner


f = outter(1)  # f = inner  ,x = 1

print(f)
f()
<function outter.<locals>.inner at 0x0000017E2A641048>
1

闭包函数的应用

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

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

import requests


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


baidu = outter('http://www.baidu.com')  # baidu = get

baidu()  # baidu() = get()

taobao = outter('http://www.taobao.com')  # taobao = get

taobao()
done:http://www.baidu.com
done:http://www.taobao.com

装饰器

无参装饰器

什么是装饰器

器指的是工具,而程序中的函数就是具备某一功能的工具,所以装饰器指的是为被装饰器对象添加额外功能。

注意:

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

为什么要用装饰器

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

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

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

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

怎么用装饰器

# 改变调用方式

import time


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


def time_count(func):
    start = time.time()
    func()   # index()
    end = time.time()
    print(f'{func} time is {end - start}')


time_count(index)   # 改变了index的调用方式
welcome to index
<function index at 0x0000017E2A84BD90> time is 1.0003917217254639
# 包给函数—外包

import time


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


def time_count(func):

    def wrapper():
        start = time.time()
        func()  # index()
        end = time.time()
        print(f'{func} time is {end - start}')
    return wrapper


print(index)  # <function index at 0x0000017E2A781B70>
print('*'*20)
index = time_count(index)  # index = wrapper
index()  # index() = wrapper()
print('*'*20)
print(index)  # 地址与第一个打印不同
# <function time_count.<locals>.wrapper at 0x0000017E2A8A00D0>
<function index at 0x0000017E2A781B70>
********************
welcome to index
<function index at 0x0000017E2A781B70> time is 1.0003859996795654
********************
<function time_count.<locals>.wrapper at 0x0000017E2A8A00D0>

完善装饰器

  1. 如果原始的index()有调用值,上述的wrapper()却没有,两者的返回值应该相同,我们需要同步原始函数有个返回值。
import time


def index():
    print('welcome to index')
    time.sleep(1)
    return "I'm index"


def time_count(func):
    
    def wrapper():
        start = time.time()
        res = func()  # res = index() = "I'm index"
        end = time.time()
        print(f'{func} time is {end - start}')
        
        return res
    return wrapper

print(index())
print('*'*20)
index = time_count(index)
res = index()
print(res)
welcome to index
I'm index
********************
welcome to index
<function index at 0x0000017E2A8858C8> time is 1.0053789615631104
I'm index
  1. 如果原始的函数需要传参,那么我们之前的装饰器无法实现该功能的,那么只要给wrapper()传参即可。
import time 

def home(name):
    print(f'welcome {name} to home page')
    time.sleep(1)
    
    return name
    
def time_count(func):
    
    def wrapper(*args,**kwargs):
        
        start = time.time()
        res = func(*args,**kwargs)
        end = time.time()
        print(f'{func} time is {end - start}')
        
        return res
    return wrapper


home = time_count(home)  # home = wrapper
res = home('william')  res = wrapper('william')
print(res)
welcome william to home page
<function home at 0x0000017E2A8856A8> time is 1.0003857612609863
william

装饰器语法糖

在被装饰的函数上方,单独写一行@装饰器名

# 上方函数用语法糖
import time 

def time_count(func):
    
    def wrapper(*args,**kwargs):
        
        start = time.time()
        res = func(*args,**kwargs)
        end = time.time()
        print(f'{func} time is {end - start}')
        
        return res
    return wrapper

@time_count
def home(name):
    print(f'welcome {name} to home page')
    time.sleep(1)
    
    return name

@time_count
def index():
    print('welcome to index')
    time.sleep(1)
    return "I'm index"
    

    
print(index())
print('*'*20)
print(home('william'))
welcome to index
<function index at 0x0000017E2A885E18> time is 1.0003869533538818
I'm index
********************
welcome william to home page
<function home at 0x0000017E2A885D90> time is 1.0013864040374756
william

装饰器模板

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

有参装饰器

无参装饰器只套了两层,下面是三层装饰器—有参装饰器。这个参数是装饰器的参数。

# 登陆注册(判断信息来源,'file'可以,其他不行)

is_login_dict = {'username':None}

def auth(origin):
    
    def login(func):
        
        def wrapper(*args,**kwargs):
            
            if origin == 'file':
                print('from file')
                
                if not is_login_dict.get('username'):
                    username = input('please enter your username>>>').strip()
                    print('login successfully')
                    res = func(*args,**kwargs)
                    is_login_dict['username'] = username
                    return res
                else:
                    res = func(*args,**kwargs)
                    return res
            else:
                
                print('illegal original')
        return wrapper
    return login


@auth('file')
def shopping(): 
    print('from shopping')

    
@auth('mongodb')
def withdraw():
    print('from withdraw')
    
@auth('file')
def paying():
    print('from paying')
    
    
    
shopping()   # 需要输入用户名
print('*'*20)
withdraw()   #来源错误
print('*'*20)
paying()    # 无需再次输入用户名
from file
please enter your username>>>william
login successfully
from shopping
********************
illegal original
********************
from file
from paying

转载于:https://www.cnblogs.com/WilliamKong94/p/10961928.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值