• Python基础-函数进阶


    Python之函数进阶

    1.1 命名空间

    执行以下代码,在函数外面引用函数里面的变量,会发现执行报错了

    def func1():
        m = 1
        print(m)
    print(m)  #这行报的错
    
    报错了:
    NameError: name 'm' is not defined  # m未定义

    Python执行代码原理回顾

      从Python解释器开始执行代码之后,就在内存中开辟一个空间,每当遇到一个变量的时候,就把变量名和值之间对应的关系记录下来。但是当遇到函数定义的时候,解释器只是象征性的将函数名读入内存,表示已经知道这个函数的存在了。至于函数内部的变量和逻辑,解释器根本不关心。

      等执行到函数调用语句的时候,Python解释器会在新开辟一块内存来存储这个函数里面的内容。这个时候,才关注函数里面有哪些变量。而函数中的变量会存储咋新开辟出来的内存中,函数中的变量只能在函数内部使用,并且会随着函数的执行完毕,这块内存中的内容也会被清空。

      存放变量名与值的关系的空间,就叫做---命名空间。

      代码在运行伊始,创建的存储‘变量名与值的关系’的空间,叫做全局命名空间

    在函数的运行中开辟的临时的空间,叫做局部命名空间

    1.2 命名空间和作用域

    命名空间一共分为三种:

      全局命名空间

      局部命名空间

      内置命名空间

    * 内置命名空间中存放了python为我们提供的默认的方法,比如input、len、str等等

    1.2.1 命名空间的加载顺序

    内置命名空间(程序运行前加载) --> 全局命名空间(程序运行中,从上到下加载) -->局部命名空间(程序运行中,调用函数时才加载)

    1.2.2 命名空间的取值顺序

      在局部调用:局部命名空间 --> 全局命名空间 --> 内置命名空间

      在全局调用: 全局命名空间 --> 内置命名空间  (无法调用到局部命名空间)

    综上所诉,在寻找变量时,从小范围,一层一层到大范围去寻找

    1.2.3 作用域

    作用域就是作用范围,按照生效范围可以分为全局作用域局部作用域

    全局作用域:

      包含内置命名空间、全局命名空间,在整个文件的任意位置都能被引用,全局有效。

    局部作用域:

      局部命名空间,只能在局部范围内生效

    1.2.4 global nonlocal

    执行以下代码会报错,为什么呢?

    count = 1
    def func1():
        count = count + 1
        print(count)
    func1()

    因为count是全局变量,在函数中不能直接对全局变量进行更改

    global

    name = 'wusir'
    def func1():
        global name
        name = 'alex'
        return
    func1()
    print(name)
    # # global 1,在函数中声明一个全局变量
    # # 2,在函数中更改一个全局变量

    nonlocal

    def func1():
        name1 = 'alex'
        print('+',name1)
        def inner():
            nonlocal name1
            name1= 'wusir'
            print('*',name1)
            def inner1():
                pass
        inner()
        print('%',name1)
    func1()

    nonlocal 在子函数中声明、更改一个外层的局部变量

    1.3 函数名的操作

    1.3.1 函数名的赋值

    # 函数名可以相互赋值
    def func1():
        print(666)
    
    f1 = func1
    f1()

    1.3.2 函数名做参数

    # 函数名可以当成其他函数的参数
    def func1():
        print(666)
    
    def func2(argv):
        argv()
        print(777)
    
    func2(func1)

    1.3.3 函数名可以当成容器类数据类型的参数

    # 函数名当做数据类型的参数
    def func1():
        print(666)
    def func2():
        print(777)
    def func3():
        print(888)
    
    l1 = [func1, func2, func3]
    for i in l1:
        i()

    1.3.4 函数名当做函数的返回值

    def func1():
        print(666)
    
    def func2(argv):
        print(777)
        return argv
    
    ret = func2(func1)
    ret()

    1.4 闭包

    闭包的简单定义:内层函数对外层函数非全局变量的引用,叫做闭包。

    闭包的好处:python的一个机制,如果python检测到闭包,它的局部作用域是不会随着函数的结束而结束的。

    判断一个函数是否闭包的方法:

    def wrapper():
        name1 = '老男孩'
        def inner():
            print(name1)
        inner()
        print(inner.__closure__)  # cell
    wrapper()
    ###输出结果
    老男孩
    (<cell at 0x101a950a8: str object at 0x1040e58d0>,)   #检测结果是 闭包
    # name1 是外层函数wrapper中的变量,是局部变量。
    
    name1 = '老男孩'
    def wrapper():
        def inner():
            print(name1)
        inner()
        print(inner.__closure__)  # None
    wrapper()
    ### 输出结果
    老男孩
    None    ##检测结果 不是闭包
    # name1 是全局变量。
    
    name = 'alex'
    def wrapper(argv):
        def inner():
            print(argv)
        inner()
        print(inner.__closure__)  # cell
    wrapper(name)
    ### 输出结果
    alex
    (<cell at 0x101a950a8: str object at 0x101eb9618>,)
    上述函数也是闭包 为什么呢?
    因为:
    函数中argv接收的names的变量,等于是在函数中重新定义了一个变量:args='alex' ,仍旧是一个局部变量,所有仍旧形成了闭包

    闭包的用处:  

      python的一个机制,如果python检测到闭包,它的局部作用域是不会随着函数的结束而结束的。

        因为有以上机制,如果你需要执行爬虫,不会每次都新开内存。第一次运行爬虫后,会把爬取的内容计入内存。下次爬取的时候,因为局部作用域没有关闭,所以可以直接读取到内存中的内容。

    闭包的另一大用处:装饰器!

    1.5 装饰器

    1.5.1 认识装饰器

    写学习写一个最简单的装饰器

    ## 简单的装饰器
    def timer(f1):
        def inner():
            sta_time = time.time()
            f1()
            end_time = time.time()
            print('代码执行效率为%s' %(end_time - sta_time))
        return inner
    
    @timer # <==> func1 = timer(func1)
    def func1():
        print("晚上回去吃烧烤")
        time.sleep(0.3)
    
    @timer
    def func2():
        print('晚上喝啤酒')
        time.sleep(0.5)
    
    
    func1()
    func2()

    装饰器的作用:在不改变原函数及原函数的调用的情况下,为原函数增加一些额外的功能,如打印日志、执行时间、登录认证。

    1.5.2 带参数的装饰器

    # 带函数的装饰器
    def timer(f1):
        def inner(*args, **kwargs):
            sta_time = time.time()
            f1(*args, **kwargs)
            end_time = time.time()
            print('代码执行效率为%s' % (end_time - sta_time))
    
        return inner
    
    @timer  #func3 = timer(func3)
    def func3(a, b):
        print(a, b)
        time.sleep(0.2)
    
    func3('', '鸿')

     

  • 相关阅读:
    Ubuntu 网络代理配置
    WSL2 环境配置
    两台笔记本电脑实现同一wifi下虚拟主机网络实现互通
    Linux /dev/loop0文件详解
    Excel两张表查重,返回True
    计算机网络基础/进制转换/企业级子网IP划分
    leetcode 2030. 含特定字母的最小子序列
    nginx https
    kubernetes(二十四)ingress https
    求两个向量的旋转矩阵 E
  • 原文地址:https://www.cnblogs.com/wangph/p/8875544.html
Copyright © 2020-2023  润新知