一、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的资料请关注Devmax其它相关文章!

Python基础globlal nonlocal和闭包函数装饰器语法糖的更多相关文章

  1. XCode 3.2 Ruby和Python模板

    在xcode3.2下,我的ObjectiveCPython/Ruby项目仍然可以打开更新和编译,但是你无法创建新项目.鉴于xcode3.2中缺少ruby和python的所有痕迹(即创建项目并添加新的ruby/python文件),是否有一种简单的方法可以再次安装模板?我发现了一些关于将它们复制到某个文件夹的信息,但我似乎无法让它工作,我怀疑文件夹的位置已经改变为3.2.解决方法3.2中的应用程序模板

  2. swift之ARC

    Swift使用自动引用计数来跟踪并管理应用使用的内存。大部分情况下,这意味着在Swift语言中,内存管理"仍然工作",不需要自己去考虑内存管理的事情。为了保证不会发生上述的情况,ARC跟踪与类的实例相关的属性、常量以及变量的数量。解决实例间的强引用环Swift提供两种方法来解决强引用环:弱引用和无主引用。在Swift语言中,推荐用可选类型来作为可能没有值的引用的类型。

  3. Swift的函数与函数指针、闭包Closure等相关内容介绍

  4. 《The Swift Programming Language》2.0版之自动引用计数

    Swift1.0文档翻译:TimothyYeSwift1.0文档校对:HawsteinSwift2.0文档校对及翻译润色:ChannePS:之前1.0版中文版看不懂地方在对比英文版后就懂了,还是之前翻译的不够准确啊。,而不是Person),它们的值会被自动初始化为nil,目前还不会引用到Person类的实例。由于Person类的新实例被赋值给了reference1变量,所以reference1到Person类的新实例之间建立了一个强引用。在你将john和number73赋值为nil后,强引用关系如下图:P

  5. Swift基本使用-函数和闭包(三)

    声明函数和其他脚本语言有相似的地方,比较明显的地方是声明函数的关键字swift也出现了Python中的组元,可以通过一个组元返回多个值。传递可变参数,函数以数组的形式获取参数swift中函数可以嵌套,被嵌套的函数可以访问外部函数的变量。可以通过函数的潜逃来重构过长或者太复杂的函数。

  6. Swift排序Sort函数用法

    简书地址:http://www.jianshu.com/p/ad71c94e7bc6摘自stackoverflow的问答用了几分钟做的简单翻译一个例子直接贴代码,不过多解释下面是闭包的进阶使用

  7. Swift2.0初见笔记

    Swift2.01.简单值1.使用let来声明常量,常量无法改变;使用var来声明变量.2.常量或者变量的类型必须和你赋给它们的值一样。后面的东西都会被忽略,并且整个表达式返回nil。在switch里,枚举成员使用缩写.Hearts来引用,因为self的值已经知道是一个suit。SimpleClass的声明不需要标记任何方法因为类中的方法经常会修改类。

  8. 10 个Python中Pip的使用技巧分享

    众所周知,pip 可以安装、更新、卸载 Python 的第三方库,非常方便。本文小编为大家总结了Python中Pip的使用技巧,需要的可以参考一下

  9. Swift2.1-自动引用计数

    官方文档Swift使用自动引用计数机制来追踪和管理你的app的内存。在大多数情况,这意味着Swift的内存管理机制会一直起作用,你不需要自己考虑内存管理。注意引用计数只应用于类的实例。因此,当你断开john和unit4A变量所持有的强引用时,引用计数并不会降为0,实例也不会被ARC销毁:注意,当你把这两个变量设为nil时,没有任何一个析构函数被调用。若引用不能声明为常量。在Swift中,推荐使用可选类型描述可能没有值的类型。

  10. Swift 编程语言入门教程

    Swift是供iOS和OSX应用编程的新编程语言,基于C和Objective-C,而却没有C的一些兼容约束。Swift采用了安全的编程模式和添加现代的功能来是的编程更加简单、灵活和有趣。Swift已经存在了多年。基于这些基础,Swift引入了很多新功能和结合面向过程和面向对象的功能。Swift对新的程序员也是友好的。Swift集成了现代编程语言思想,以及Apple工程文化的智慧。Swift是编写iOS和OSX应用的梦幻方式,并且会持续推进新功能的引入。2Swift入门一个新语言的学习应该从打印"Hello

随机推荐

  1. 10 个Python中Pip的使用技巧分享

    众所周知,pip 可以安装、更新、卸载 Python 的第三方库,非常方便。本文小编为大家总结了Python中Pip的使用技巧,需要的可以参考一下

  2. python数学建模之三大模型与十大常用算法详情

    这篇文章主要介绍了python数学建模之三大模型与十大常用算法详情,文章围绕主题展开详细的内容介绍,具有一定的参考价值,感想取得小伙伴可以参考一下

  3. Python爬取奶茶店数据分析哪家最好喝以及性价比

    这篇文章主要介绍了用Python告诉你奶茶哪家最好喝性价比最高,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧

  4. 使用pyinstaller打包.exe文件的详细教程

    PyInstaller是一个跨平台的Python应用打包工具,能够把 Python 脚本及其所在的 Python 解释器打包成可执行文件,下面这篇文章主要给大家介绍了关于使用pyinstaller打包.exe文件的相关资料,需要的朋友可以参考下

  5. 基于Python实现射击小游戏的制作

    这篇文章主要介绍了如何利用Python制作一个自己专属的第一人称射击小游戏,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起动手试一试

  6. Python list append方法之给列表追加元素

    这篇文章主要介绍了Python list append方法如何给列表追加元素,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  7. Pytest+Request+Allure+Jenkins实现接口自动化

    这篇文章介绍了Pytest+Request+Allure+Jenkins实现接口自动化的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  8. 利用python实现简单的情感分析实例教程

    商品评论挖掘、电影推荐、股市预测……情感分析大有用武之地,下面这篇文章主要给大家介绍了关于利用python实现简单的情感分析的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下

  9. 利用Python上传日志并监控告警的方法详解

    这篇文章将详细为大家介绍如何通过阿里云日志服务搭建一套通过Python上传日志、配置日志告警的监控服务,感兴趣的小伙伴可以了解一下

  10. Pycharm中运行程序在Python console中执行,不是直接Run问题

    这篇文章主要介绍了Pycharm中运行程序在Python console中执行,不是直接Run问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

返回
顶部