首页 > 编程语言 >python基础之闭包函数与装饰器

python基础之闭包函数与装饰器

时间:2022-10-11 20:45:43浏览次数:58  
标签:index 函数 python res 之闭 time print 装饰 def

python基础之闭包函数与装饰器

目录

一、global与nonlocal

money = 66  # 全局空间


def index():
    money = 123
    
    
index()
print(money)
image-20221011145926078
1.global 局部名称空间直接修改全局名称空间中的数据(不可变类型:整型、字符串和元组)

# 案例1
money = 66  # 全局空间

def index():
    global money  # global作用 局部名称空间直接修改全局名称空间中(不可变类型)的数据,此时函数体代码内的数据值可以绑定全局名称空间中的变量名
    money = 123
    
index()
print(money)  # 此时 money = 123

# 案例2 
money = 66  # 全局空间
l1 = [11,22,33]
def index():
    l1.append(44)  # 此时修改的是全局的l1,列表为可变类型的数据
    
index()
print(l1)

只有赋值语法才涉及 名称存放 和 在 名称空间查找名字 的问题

2.nonlocal 内层局部名称空间 修改 外层局部名称空间中的数据
# 案例1
 # 不使用关键字nonlocal
def index():
    name = 'jason'
    def inner():
        name = 'tom'
    inner()
    print(name)
index() # jason 

# 使用关键字nonlocal
def index():
    name = 'jason'
    def inner():
        nonlocal name  # 内层局部名称空间 修改 外层局部名称空间中的数据
        name = 'tom'
    inner()
    print(name)
index()  # 函数index 局部名称空间中 name = tom
image-20221011152158989

二、函数名的多种用法

函数可以被当作“数据”来处理,此时可以将函数名看作是变量名

  函数名其实绑定的也是一块内存地址,只不过改地址里面存放的不是数据值,而是一段代码,函数名加括号可以去调用这段代码
  
# 案例1
def index():
    print('from index')
print(index)  # <function index at 函数名所绑定的内存地址>



1.可以当变量名

1.可以当作变量名赋值
# 案例2
def index():
    print('from index')
res = index  # 将res绑定向index函数
res()  # res也具备调用index的能力

2.可以当函数的参数

2.可以当作函数的参数传值进去
# 案例3
def index():
    print('from index')
def func(a):
    print(a)
    a()
func(index)
image-20221011153642125

print(函数名) 为打印 该函数的内存地址

print(函数名()) 为打印该函数的返回值

3.可以当函数的返回值

3.可以当作函数的返回值
 1)返回值是数据值时,直接返回
# 案例4 
def index():
    print('from index')
    
def func():
    print('from func')
    return 123

res = func()
print(res)  # 123

 2)返回值是函数名时,赋值于其他变量名可以利用该变量名调用函数
  ( 1 )两个函数套娃
# 案例5
def index():
    print('from index')
    
def func():
    print('from func')
    return index

res = func()
print(res)
res()  # from index
10.11 插图4.png
 ( 2 )函数嵌套
# 案例6
def index():
    print('from index')
    def func():
        print('from func')
    return func
  
res = index()
print(res)
res()  # 让res也绑定向func绑定的值,res也能调用func中的
image-20221011161834717

函数嵌套时,名称空间的绑定关系

image-20221011164212194

4.可以当作容器类型(可以存放多个数据的数据类型:列表、元组、字典、集合)的数据
# 案例6
def index():
    print('from index')

l1 = [11, 22, 11.11, 'jason', index]
l1[-1]()  # from index
# 通过索引 列表中 的 元素 函数名 去调用函数

# 案例7 通过将函数名保存在字典中,索引函数名 使用函数功能
def register():
    print('注册功能')


def login():
    print('登录功能')


def withdraw():
    print('提现功能')


def transfer():
    print('转账功能')


def shopping():
    print('购物功能')


# 定义功能编号与功能的对应关系
func_dict = {
    '1': register,
    '2': login,
    '3': withdraw,
    '4': transfer,
    '5': shopping
}

while True:
    print("""
        1.注册功能
        2.登录功能
        3.提现功能
        4.转账功能
        5.购物功能
        """)
    choice = input('>>>:').strip()
    if choice in func_dict:
        func_dict.get(choice)()
    else:
        print('功能编号不存在')
image-20221011171930571

三、闭包函数

闭包函数:定义在函数内部的函数,并且用到了外部函数空间的名字
  也就是函数被当作数据处理的时候,始终以自带的作用域为准,若内嵌函数包含外对外部函数作用域中变量的引用,那么该'内嵌函数'就是闭包函数
'''	满足的要求:
  1.定义在函数内部
  2.用到了外部函数名称空间的名字(变量名)'''
# 案例1 
def index():
    print('jason')
    def inner():
        print(name)  # 是变量名而不是数据值

1.闭包函数的实际应用

1.闭包函数是另一种给函数体代码传参的方式

# 函数体传参的方式一:代码里面缺什么变量名就在形参中补充什么变量名
def register(name, age):
    print(f'''
    name:{name}
    age:{age}
    ''')
  
# 函数体传参的方式二:闭包函数
def outer():
    name = 'jason'
    age = 12
    def register(name, age):
        print(f'''
        name:{name}
        age:{age}
        ''')
    return register
res = outer()
# 闭包函数特点1:不会受外界变量名的影响
10.11 插图9.png

当第5步的x 没有被使用时,会变灰,即pycharm提示当前程序内并没有使用到这个对象,只要在程序内没有其他代码使用它的时候就会变灰来表示没有被引用可以删除不占用资源

# 闭包函数的特点2:绑定一次数据值可以重复使用
def outer(name, age):
    def register(name, age):
        print(f'''
        name:{name}
        age:{age}
        ''')
    return register
res = outer('jason', 18)
res()
res()
res = outer('kevin', 38)
res()
res()
res()
image-20221011184817270 image-20221011185247791

1.在1次传参后,可以重复使用
2.可以通过改变传进去的参数,对结果进行更改

四、装饰器

1.装饰器简介

1.概念
    在不改变被装饰对象原代码和调用方式的情况下,给被装饰对象添加新的功能
  """
  软件包含功能的源代码以及调用方式,都应该避免修改,避免出错。
  而对于上线后的软件,新需求则意味着扩展的可能性,应该为程序提供扩展的可能性
  """
2.本质
    并不是一门新的技术,而是由函数参数、名称空间、函数名多种用法、闭包函数组合到一起的结果
3.装饰器口诀
    对修改封闭,对扩展开放
   """
  软件的设计应该遵循开放封闭原则,对扩展开放,对修改封闭。对扩展开放意味着有新的需求或者变化时,可以对现有代码进行扩展,以适应新的情况。对修改封闭,意味着对象一旦设计完成,就可以独立完成其工作,而不要对其进行修改。
  """
4.储备知识
    时间相关操作 
 1)时间戳 time.time
import time
print(time.time())  # 时间戳(距离1970-01-01 00:00所经历的秒数)
 2)时间阻塞 time.sleep()
import time
time.sleep()

2.装饰器推导流程

# 案例
import time
def index():
    time.sleep(3)
    print('from index')
def home():
    time.sleep(1)
    print('from home')

如果想为案例中的代码添加新的功能,该如何实现?

1.直接在调用index函数前后添加新功能的代码

import time
def index():
    time.sleep(3)
    print('from index')
def home():
    time.sleep(1)
    print('from home')
    
start_time = time.time()
index()
end_time = time.time()
print('函数index的执行时间为:', end_time-start_time)

如果想要多次调用index函数如何实现新功能,该如何实现?

2. 建立新功能的函数实现多次调用index函数新功能

相同的代码不同位置反复执行==>>> 函数
定义新功能为函数,即可通过调用函数多次使用新功能

def get_time():
    start_time = time.time()
    index()
    end_time = time.time()
    print('函数index的执行时间为:', end_time - start_time)


get_time()
image-20221011191952414

但是这样函数体代码不够灵活,只能对index函数使用,如何对其他函数使用?

3.使用参数可以传参变换统计的函数

利用参数,将统计的函数名传给参数,变换传参即变化统计的函数

def get_time(v):
    start_time = time.time()
    v()
    end_time = time.time()
    print('函数index的执行时间为:', end_time - start_time)


get_time(home)
get_time(index)
---------------res--------------------
from home
函数index的执行时间为: 1.003127098083496
from index
函数index的执行时间为: 3.0050511360168457

如何通过调用函数的方式,去使用新功能?

4.使用闭包函数来调用新功能

通过闭包函数来将调用函数的方便变简便

def outer(v):
    def get_time():
        start_time = time.time()
        v()
        end_time = time.time()
        print('函数index的执行时间为:', end_time - start_time)
    return get_time

res = outer(index)
res()
res = outer(home)
res()
---------------res--------------------
from index
函数index的执行时间为: 3.005207061767578
from home
函数index的执行时间为: 1.004741907119751

如何使用原函数名来调用具有新功能的函数?

5.使用赋值语句使调用原函数名时具有新功能

将原函数名 绑定向 扩展了新功能的函数体代码
def outer(v):
    def get_time():
        start_time = time.time()
        v()
        end_time = time.time()
        print('函数index的执行时间为:', end_time - start_time)
    return get_time

index = outer(index)
index()
home = outer(home)
home()
---------------res--------------------
from index
函数index的执行时间为: 3.005207061767578
from home
函数index的执行时间为: 1.004741907119751
image-20221011200429696

如果想调用有参函数怎么办?

6.为闭包函数引入参数,兼容有参函数,以及有返回值的函数

---------------res--------------------
from index
函数index的执行时间为: 3.005207061767578
from home
函数index的执行时间为: 1.004741907119751将函数的类型丰富
import time

def index(a):
    time.sleep(3)
    print('from index',a)
    return 'index'  # 


def outer(res):
    def get_time(*args,**kwargs):
        start_time = time.time()
        res(*args,**kwargs)
        end_time = time.time()
        print('函数index的执行时间为:', end_time - start_time)
        return res
    return get_time


index = outer(index)
res = index(1)
print(res)
---------------res--------------------
from index 1
函数index的执行时间为: 3.005103826522827
<function index at 0x1007c9430>

3.装饰器模版


def outer(func):
    def inner(*args, **kwargs):
        # 执行被装饰对象之前可以做的额外操作
        res = func(*args, **kwargs)
        # 执行被装饰对象之后可以做的额外操作
        return res
    return inner

4.装饰器语法糖

用符号@装饰器的函数名,调用该装饰器,且把它正下方的函数名当作是参传入,然后将返回的结果重新赋值给原函数名
def outer(func):
    def inner(*args, **kwargs):
        # 执行被装饰对象之前可以做的额外操作
        res = func(*args, **kwargs)
        # 执行被装饰对象之后可以做的额外操作
        return res
    return inner
"""
语法糖 @装饰器的函数名,调用该装饰器,且把它正下方的函数名当作是参传入,然后将返回的结果重新赋值给原函数名
"""
@outer  # func = outer(func)
def func():
    print('from func')
    return 'func'

aa ```python

aaa

image-20221011113054290

5

image-20221011114132492

7

image-20221011115157515

装饰器模版

装饰器模版糖

标签:index,函数,python,res,之闭,time,print,装饰,def
From: https://www.cnblogs.com/DuoDuosg/p/16782495.html

相关文章

  • 装饰器
    1.global与nonlocal1.global:局部名称空间修改全局名称空间的数据n=100defindex():globalnn=999index()print(n)#9992.nonlocal:内层局部名......
  • python重点之装饰器
    global与nonlocal函数名的多种用法闭包函数装饰器简介无参装饰器有参装饰器装饰器模板装饰器语法糖今日详细内容global与nonlocalmoney=666defind......
  • 装饰器、global与nonlocal
    目录global与nonlocal函数名的多种用法闭包函数装饰器简介装饰器推导流程装饰器模版装饰器语法糖作业global与nonlocalglobalmoney=666defindex():globalmone......
  • python进阶之路11 闭包函数 装饰器
    函数名的多种用法函数名其实绑定的也是一块内存地址只不过该地址里面存放的不是数据值而是一段代码函数名加括号就会找到该代码并执行1.可以当作变量名赋值defindex......
  • Python爬虫-scrapyd框架部署
    爬虫项目部署1脚本文件部署linux内置的cron进程能帮我们实现这些需求,cron搭配shell脚本,非常复杂的指令也没有问题。1.1crontab的使用crontab[-uusername]/......
  • 函数名的用法,闭包函数与装饰器
    函数的多种用法与装饰器global与nonlocal1.global用在局部名称空间直接修改全局名称空间中的数据x=111deffunc():globalx#修改全局名称空间x值x=2......
  • Python基础12
    今日内容概要global与nonlocal函数名的多种用法闭包函数装饰器简介装饰器推导流程装饰器模板装饰器语法糖今日内容详细global与nonlocal'''通过global声明可......
  • 装饰器+闭包掌握(python一大重要功能)
    目录global与nonlocal函数名的多种用法闭包函数装饰器简介1.概念2.本质3.口诀4.超前知识time模块装饰器推导装饰器模板装饰器语法糖作业global与nonlocalglobal#提升......
  • Java设计模式之 装饰模式实验报告书
    Java设计模式之装饰模式实验报告书姓名:班级:学号:实验三:装饰模式的应用一、实验目的熟练使用JAVA实现装饰模式,理解设计模式的模式动机,掌握模式结构,学习如何使用代码实现......
  • 函数装饰器
    global与nonlocalmoney=666defindex():globalmoneymoney=123index()print(money)"""局部名称空间直接修改全局名称空间中的数据"""defindex(......