返回顶部
首页 > 资讯 > 后端开发 > Python >Python基础globlalnonlocal和闭包函数装饰器语法糖
  • 589
分享到

Python基础globlalnonlocal和闭包函数装饰器语法糖

2024-04-02 19:04:59 589人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

目录一、global与nonlocal1、global2、nonlocal二、函数名的多种用法三、闭包函数1、什么是闭包函数2、闭包函数需满足的条件3、闭包函数的作用4、闭包函数的实

一、global与nonlocal

1、global

  • 在py文件中,一般无法调用函数体内变量名,而global可使函数体代码内的变量名直接在函数体外部调用,条件是在需要调用的代码体中使用global 调用需要的变量名

未使用global情况:

# 在外部绑定一个变量名
name = 'kangkng'
# 定义一个函数体代码
def func():
    # 函数体内部重新绑定一个变量名
    name = 'zhangzhang'
# 调用函数func
func()
# 这时无法打印函数体内部的变量名
print(name)
------------------------------------------------------------------------ kangkang   

使用global情况:

# 在函数体内部使用global时,可在外部直接调用函数内部变量名
name = 'kangkng'
# 定义一个函数体代码
def func():
    # 使用global调用变量名
    global name
    # 函数体内部重新绑定一个变量名
    name = 'zhangzhang'
# 调用函数func
func()
# 外py中打印name
print(name)
------------------------------------------------------------------------
zhangzhang

2、nonlocal

  • 在函数嵌套使用时,通常在父代码体中无法调用子代码中变量名,

而nonlocal的作用是,可以在父代码中直接调用子代码中的变量名,条件是需要在子代码中使用nonlocal 调用需要的变量名

未使用nonlocal情况:

# 定义一个函数体代码
def outer():
    # 绑定一个变量名
    name = 'kangkang'
    # 代码体内部再次定义一段函数体
    def subcoat():
        # 内层中绑定变量名
        name = 'zhangzhang'
    # 在函数外层打印变量名
    print(name)
# 调用外层函数体代码
outer()
----------------------------------------------------------------------- 
kangkang

使用nonlocal情况:

# 在函数体内部使用global时,可在外部直接调用函数内部变量名
def outer():
    # 函数外层绑定一个变量名
    name = 'kangkang'
    # 代码体内部再次定义一段函数体
    def subcoat():
        # 在函数体内层使用nonlocal,调用变量名
        nonlocal name
        # 内层中绑定变量名
        name = 'zhangzhang'
    # 调用内层函数
    subcoat()
    # 在函数外层打印变量名
    print(name)
# 调用外层函数体代码
outer()   
----------------------------------------------------------------------
zhangzhang

二、函数名的多种用法

引言:

​ 函数名就相当于变量名,只不过函数名绑定的是一段函数体代码,在我们使用这个函数名加括号时就可以调用这段代码体,具体由以下几种用法:

1、当做变量名赋值

def func():
    print('我是func函数体代码')
res = func
print(res())
------------------------------------------------------------------------
我是func函数体代码
None

2、当作函数的参数

def func():
    print('我是func函数体代码')
def func1(a):
    print('我是func1函数体代码', a)
    a()
func1(func)
------------------------------------------------------------------------
我是func1函数体代码 <function func at 0x000001D0C14D6310>
我是func函数体代码

3、当作函数的返回值

def func():
    print('我是func函数体代码')
def func1():
    print('我是func1函数体代码')
    return func
res = func1()
print(res)
res()
------------------------------------------------------------------------
我是func1函数体代码
<function func at 0x00000218F95B6310>
我是func函数体代码

4、当作容器类型的数据

def spring():
    print('我是春季,生机盎然')
def summer():
    print('我是夏季,活力四射')
def autumn():
    print('我是秋季,翩翩起舞')
def winter():
    print('我是冬季,大雪纷飞')
while True:
    season_dict = { '1': spring,
               '2': summer,
               '3': autumn,
               '4': winter
                   }
    season_select = input('根据编号,选择您喜欢的季节>>>:').strip()
    if season_select in season_dict:
        season_dict.get(season_select)()
    else:
        print('你选择的编号不存在')
------------------------------------------------------------------------

三、闭包函数

1、什么是闭包函数

  一个函数的返回值是另外一个函数,返回的函数调用父函数内部的变量,如果返回的函数在外部被执行,就产生了闭包

2、闭包函数需满足的条件

满足以下两个条件的就是闭包函数:

条件一:定义在函数内部的函数

条件二:用到了外部函数空间名称中的名子

3、闭包函数的作用

作用:使函数外部能够调用函数内部放入属性和方法

缺点:闭包操作导致整个函数的内部环境被长久保存,占用大量内存

4、闭包函数的实际应用

1.函数内部变量名在外部被访问

def fun1():
    name = 'python'
    def inner():
        print(name)
    return inner
result = fun1()
result()
------------------------------------------------------------------------
Python

2.函数体内部函数体代码可以通过外部访问

def fun2():
    def inner():
        print("执行了内部函数inner")
    def all():
        return inner
    return all
result = fun2()
result()()
------------------------------------------------------------------------
执行了内部函数inner

四、装饰器

​ 当我们需要将一段函数体代码在不改变调用方式和源代码的情况下,需要给这个段代码添加新的功能时,这时候我们就需要给这段代码安装一个装饰器,装饰器是指将这段代码封装在闭包函数内,来达到既能满足上述条件,又能增加新的功能的条件

概念

  • 在不修改被装饰对象源代码和调用方式的情况下给被装饰的对象添加新的功能

本质

  • 并不是一门新的技术,而是由函数参数、名称空间、函数名多种用法、闭包函数组合到一起的效果

口诀

  • 对修改封闭,对扩展开放

1、装饰器推导流程

1、首先定义一段函数体代码,当我们给这段函数传入指定的参数时,他就会暂停一秒,然后运行,使它在运行结束后,能够统计它的运行时间

import time
def index(a, b):
    time.sleep(1)
    print(index,a, b)

2、通常,我们只需要在这段代码运行前打印一个时间戳,运行后再次打印一个时间戳,在这段代码运行结束后通过前后时间的插值就能统计出这段代码的运行时间,但这种办法使用起来比较麻烦且只能使用一次

方法一:
    import time
    def index(a, b):
        start = time.time()
        time.sleep(1)
        print(index, a, b)
        end = time.time()
        print(end - start)
    index(1,2)
方式二:
    import time
    def index(a, b):
        time.sleep(1)
        print(index, a, b)
    start = time.time()
    index(1,2)
    end = time.time()
    print(end - start)

3、通过上述方法的方式二,我们可以得出将函数名包裹在统计时间功能代码内,这样在调用时相对便捷,进一步思考,若将这段代码使用函数封包,那样在调用时就可以更为便捷,在以后统计该代码时,只需要调用封包这段代码的函数名就可以直接统计这段代码的运行时间

import time
def index(a, b):
    time.sleep(1)
    print(index, a, b)
def time_():
    start = time.time()
    index()
    end = time.time()
    print(end - start)
time_()
------------------------------------------------------------------------
Traceback (most recent call last):
  File "D:/pytcharm项目文件路径/38/11.py", line 297, in <module>
    time_()
  File "D:/pytcharm项目文件路径/38/11.py", line 293, in time_
    index()
TypeError: index() missing 2 required positional arguments: 'a' and 'b'

4、虽然这种方式可以行得通,但只能针对没有参数的函数体代码,若这段代码需要传参者无法运行,并直接报错。再次进一步思考,只需要将封包的这段函数设置为有参函数就可解决这个问题

import time
def index(a, b):
    time.sleep(1)
    print(index, a, b)
def core(a,b):
    start = time.time()
    index(a, b)
    end = time.time()
    print(end - start)
core(1, 2)
------------------------------------------------------------------------
<function index at 0x000001F4A0026310> 1 2
1.0047826766967773

5、由上推导可看出,虽然此功能可以更为便捷的统计代码执行时间,但若是源代码的参数需要修改则封包它的参数也需要修改,这时我们可联想到将参数修改为可变长参数,就不会出现这个问题

import time
def index(a, b):
    time.sleep(1)
    print(index, a, b)
def core(*args,**kwargs):
    start = time.time()
    index(*args, **kwargs)
    end = time.time()
    print(end - start)
core(1,2)
------------------------------------------------------------------------
<function index at 0x000002ECDD4E6310> 1 2
1.004744529724121

6、这样无论源代码参数如何修改,我们都可以进行传参,虽然这个问题解决了,但考虑使用的广泛性,若有其他函数体也需要用到这个功能时,还需要重新修改封包内代码,这时,我们可以使用闭包的方式来满足这个条件

import time
def index(a, b):
    time.sleep(1)
    print(index, a, b)
def func(x, y, z):
    time.sleep(2)
    print(func, x, y, z)
def outer(index):
    def core(*args, **kwargs):
        start = time.time()
        index(*args, **kwargs)
        end = time.time()
        print(end - start)
    return core
res = outer(func)
res(1, 2, 3)
------------------------------------------------------------------------
<function func at 0x0000018C23686670> 1 2 3
2.00856614112854

7、通过将源代码函数名放至闭包函数参数内,就可以达到可以调动任何函数体代码都可以执行此功能的方法,但并未满足闭包函数的条件,源代码的调用方式改变了,这时我们可以通过将原函数体代码赋值的方式来达到调用方式和源代码都未改变的情况下来增加此功能

import time
def index(a, b):
    time.sleep(1)
    print(index, a, b)
def func(x, y, z):
    time.sleep(2)
    print(func, x, y, z)
def outer(index):
    def core(*args, **kwargs):
        start = time.time()
        index(*args, **kwargs)
        end = time.time()
        print(end - start)
    return core
index = outer(index)
index(1,2)
func = outer(func)
func(1, 2, 3)
------------------------------------------------------------------------
<function outer.<locals>.core at 0x0000026C17F58280> 1 2
1.004807710647583
<function outer.<locals>.core at 0x0000026C17F58940> 1 2 3
2.0077626705169678

8、虽然上述推导过程都已满足装饰器条件,但是考虑到源代码有返回值的情况,我们没有并没有获取,这时在进一步推导,可在装饰器函数内部调用源代码函数名的位置设置一个变量名用于接收返回值,传给装饰器底层return用于接收即可解决这个问题

import time
def index(a, b):
    time.sleep(1)
    print(index, a, b)
    return 'index'
def func(x, y, z):
    time.sleep(2)
    print(func, x, y, z)
    return 'func'
def outer(index):
    def core(*args, **kwargs):
        start = time.time()
        res = index(*args, **kwargs)
        end = time.time()
        print(end - start)
        return res
    return core
index = outer(index)
res = index(1,2)
print(res)
func = outer(func)
res = func(1, 2, 3)
print(res)
------------------------------------------------------------------------
<function outer.<locals>.core at 0x0000020C50A78280> 1 2
1.0050580501556396
index
<function outer.<locals>.core at 0x0000020C50A78940> 1 2 3
2.0094454288482666
func

2、装饰器语法糖

什么是装饰器语法糖

当我们使用装饰器调用被装饰的函数体代码时,总是需要在调用前通过赋值的方式来调用,这样的方式相对比较麻烦,这时我们就可以用到装饰器语法糖来节省时间和代码

语法糖的使用方法和条件

用法:在源代码函数体上方使用@加装饰器函数名

条件:源代码需在装饰器下方

具体用法

import time
def outer(index):
    def core(*args, **kwargs):
        start = time.time()
        res = index(*args, **kwargs)
        end = time.time()
        print(end - start)
        return res
    return core
@outer
def index(a, b):
    time.sleep(1)
    print(index, a, b)
    return 'index'
index(1,2)

3、装饰器模板

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

以上就是Python基础globlal nonlocal和闭包函数装饰器语法糖的详细内容,更多关于Python基础globlal nonlocal的资料请关注编程网其它相关文章!

--结束END--

本文标题: Python基础globlalnonlocal和闭包函数装饰器语法糖

本文链接: https://lsjlt.com/news/120887.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Python基础globlalnonlocal和闭包函数装饰器语法糖
    目录一、global与nonlocal1、global2、nonlocal二、函数名的多种用法三、闭包函数1、什么是闭包函数2、闭包函数需满足的条件3、闭包函数的作用4、闭包函数的实...
    99+
    2024-04-02
  • Python装饰器-闭包与函数装饰器
    一、闭包在学习装饰器前,需要先了解闭包的概念。形成闭包的要点:函数嵌套将内部函数作为外部函数的返回值内部函数必须要使用到外部函数的变量下面以一个计算列表平均值的案例来讲解闭包:def make_average(): # 创建一个列表,用来保...
    99+
    2023-05-14
    Python 函数 装饰器
  • Python必备基础之闭包和装饰器知识总结
    目录一、闭包1.1 三要素 1.2 语法1.3 优点1.4 缺点1.5 作用二、装饰器 Decorator2.1 定义2.2 语法2.3 本质2.4 装饰器链一、闭包 1.1 三要素...
    99+
    2024-04-02
  • python高级语法之闭包和装饰器详解
    目录一、闭包二、一个简单的例子三、装饰器3.1 简单装饰器3.1.1 使用装饰器的语法糖3.1.2 装饰器的执行时机3.2 通用装饰器3.2.1 装饰带有参数的函数3.2.2. 装饰...
    99+
    2024-04-02
  • 简析Python的闭包和装饰器
    什么是装饰器? 装饰器(Decorator)相对简单,咱们先介绍它:“装饰器的功能是将被装饰的函数当作参数传递给与装饰器对应的函数(名称相同的函数),并返回包装后的被装饰的函数”,听起来有点绕,没关系,直接...
    99+
    2022-06-04
    简析 Python
  • python总结之闭包和装饰器
    目录一、装饰器1.装饰器的简单介绍2.装饰器的解析过程二、闭包三、闭包中nonlocal语句的使用1.外部变量的引用和改写2.nolocal的使用及特点四、闭包与装饰器五、闭包的作用...
    99+
    2024-04-02
  • python中函数总结之装饰器闭包详解
    1、前言 函数也是一个对象,从而可以增加属性,使用句点来表示属性。 如果内部函数的定义包含了在外部函数中定义的对象的引用(外部对象可以是在外部函数之外),那么内部函数被称之为闭包。 2、装饰器 装饰器就是包...
    99+
    2022-06-04
    详解 函数 python
  • 一文掌握Python返回函数、闭包、装饰器、偏函数
    本篇文章给大家带来了关于Python 的相关知识,其中主要整理了高级编程的相关问题,包括了返回函数、闭包、装饰器、偏函数等等内容,下面一起来看一下,希望对大家有帮助。【相关推荐:Python3视频教程 】1.返回函数高阶函数除了可以接受函数...
    99+
    2022-06-30
    python
  • Python返回函数、闭包、装饰器、偏函数怎么使用
    今天小编给大家分享一下Python返回函数、闭包、装饰器、偏函数怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1.返...
    99+
    2023-07-02
  • python闭包和装饰器你了解吗
    目录一、闭包1. 什么是闭包?2. 形成闭包的三个条件(缺一不可)3. 闭包的原理4. 闭包的好处二、装饰器1. 什么是装饰器2. 装饰器有什么用3. 小 练 习三. 编写...
    99+
    2024-04-02
  • python3--函数名本质,函数嵌套,闭包,装饰器
    python函数的嵌套和作用域链函数的嵌套调用def max2(x,y):     m = x if x > y ...
    99+
    2023-01-30
    函数 嵌套 本质
  • python基础-内置函数-作用域-闭包
    内置函数-作用域-闭包-递归 1.几个可能用到的内置函数 查看内置函数: print(dir(__builtins__)) 常见函数: len 求长度 min 最小值 max 最大值 sorted 排...
    99+
    2023-01-31
    函数 作用 基础
  • python中*args与**kwarsg及闭包和装饰器的用法
    目录*args与**kwarsg及闭包和装饰器过程Python fun(*args,**kwargs)中*args,**kwargs参数含义及用法1. Python函数中的两种参数2...
    99+
    2024-04-02
  • Python语言基础之函数语法
    目录1 匿名函数(lambda 函数)2 python中函数的可变参数在 Python 中,函数可以通过以下语法定义和使用: def function_name(parameter1...
    99+
    2023-05-19
    Python语言基础 Python函数语法 Python函数
  • 深入理解python中的闭包和装饰器
    python中的闭包从表现形式上定义(解释)为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。 以下说明主要针对 python2.7...
    99+
    2022-06-04
    python
  • 怎么在python中使用闭包和装饰器
    本篇文章为大家展示了怎么在python中使用闭包和装饰器,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。一、闭包闭包的形成条件:函数嵌套。内部函数使用了外部函数的变量或者参数。外部函数返回了使用外 部...
    99+
    2023-06-15
  • Python的闭包和装饰器你真的了解吗
    目录闭包装饰器总结闭包 闭包就是能够读取其他函数内部变量的函数。 def test1(k, b): def test1_1(x): print(k*x+b) ...
    99+
    2024-04-02
  • python中的闭包和装饰器的使用示例
    目录函数参数闭包的构成条件基础的闭包的使用nonloal关键字的使用基础代码实现(装饰器)装饰器的基本使用装饰器的使用有参数的装饰器的使用带有返回值的装饰器带有不定长参数的装饰器带有...
    99+
    2022-11-21
    python闭包和装饰器 python装饰器
  • 【6】装饰器、闭包、偏函数、变量作用域问
            【一】、装饰器思想 装饰器是其实想增加一个函数的功能,但是又不想变动原来函数的代码,就用装饰器。 比如:我们用别人的一个函数,又不是很满意,所以用装饰器装饰一下即可。   def fun1(): print(...
    99+
    2023-01-30
    变量 函数 作用
  • python函数装饰器构造和参数传递
    目录一.闭包函数二.python装饰器构造三.python装饰器叠加四.python装饰器传参1.装饰器单个参数传递2.装饰器多个参数传递3.装饰器的不定长参数五、带返回值的装饰器前...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作