闭包函数=函数对象+函数嵌套+名称空间与作用域

内容概要

  • 函数对象
  • 函数嵌套
  • 名称空间与作用域
  • global与nonlocal
  • 闭包函数

内容详细

  • 函数对象

    # 精髓:可以把函数当成变量去使用
        # func = 内存地址
        # def func():
        #     print(‘from func‘)
    
    
    # 1.可以赋值
        # f = func
        # print(f,func)  # <function func at 0x0000019ED9B7F160> <function func at 0x0000019ED9B7F160>
        # f()  # from func
    
    # 2.可以当作函数的参数传给另外一个函数
        # def foo(x):
        #     x()
        # foo(func)  # from func 这里调用函数foo(func),这里的函数func相当于参数传给x,x()=func()
    
    # 3.可以把函数当作另一个函数的返回值
        # def foo(x):
        #     return x
        # res = foo(func)
        # print(res)  # <function func at 0x0000014696C5F160>
        # res()  # from func
    
    # 4.可以当作容器类型的一个元素
        # l = [func,]
        # print(l)
        # l[0]()  # from func
        #
        # dic = {‘k1‘:func,}
        # print(dic)
        # dic[‘k1‘]()  # from func
    
    
    # eg:
        def register():
            priint(‘注册功能实现===》‘)
        def login():
            print(‘登录功能实现===》‘)
        def withdraw():
            print(‘提现功能事项===》‘)
        func_dic = {
            ‘0‘:‘退出‘,
            ‘1‘:[‘注册‘,register],
            ‘2‘:[‘登录‘,login],
            ‘3‘:[‘提现‘,withdraw]
        }
        while True:
            choice = input(‘请输入命令编号:‘)
    
            for i in func_dic:
                print(‘%s  %s‘%(i,func_dic[i][0]))
            if choice == ‘0‘:
                break
            elif choice in func_dic:
                dic_func[choice][1]()
            else:
                print(‘编号输入错误,请重新输入‘)
    
  • 函数嵌套

    # 函数嵌套
    # 1.函数的嵌套调用:在调用一个函数的过程中又调用另一个函数
    # 取四个值中最大的值
         def max2(x,y):
             if x > y:
                 return x
             elif x < y:
                 return y
    
         def max4(a,b,c,d):
         # 比较a,b,大的值赋值给res1
             res1 = max2(a,b)
         # 比较res1,c,大的值赋值给res2
             res2 = max2(res1,c)
         # 比较res2,d,大的值赋值给res3
             res3 = max2(res2,d)
             return  res3
         res = max4(1,2,3,4)
         print(res)
    
    # 2.函数的嵌套定义:在函数内定义函数
    # 求圆的面积和圆的周长
    # 定义圆的面积 pi*(radius**2)
        from math import pi
        def circle(radius,mode = 0):
            def perimimter(radius):
                return 2 * pi *radius
            def area(radius):
                return pi * (radius ** 2)
            if mode == 0:
                return 2 * pi *radius
            elif mode == 1:
                return pi * (radius ** 2)
        res = circle(30,0)
        print(res)
    
  • 名称空间与作用域

    # 一、名称空间namespaces,存放名字的地方,是对栈区的划分
    #	  有了名称空间之后,就可以在栈区中存放相同的名字
    # (1)详细的名称空间分为3种:
    	# 1.内置名称空间:
        	# 存放的名字:存放的python解释器的名字:
                 ‘‘‘
                 >>> print
                 <built-in function print>
                 >>> input
                 <built-in function input>
                 ‘‘‘
        	# 存活的周期:python解释器启动则产生,关闭则销毁
                ‘‘‘python解释器启动==>将文件内容当作普通的文本内容读到内存
                ==>开始识别python语法,也就是开始运行python代码,识别函数名、模块名等
                ‘‘‘
        # 2.全局名称空间:
        	# 存放的名字:运行*代码所产生的名字,不是函数定义,也不是内置的,剩下的都是全局名称空间
            # 存活的周期:python文件执行则产生,运行完毕则销毁
                # import os
                # x=4
                # if x>3:
                #     y=20
                #     if 3==3:
                #         c=2
                # def func():
                #     a=1
                # class foo:
                #     pass
                # 以上除了 a=1,pass都是*代码
                
        # 3.局部名称空间:
        	# 存放的名字:在调用函数时,运行函数体代码过程种产生的函数内得名字
            # 存活得周期:在调用函数时存活,函数调用完毕时则销毁
            	def func():
                    a = 1
                 func() # 在此时调用函数时才存活,产生名字,且调用几次产生几个名字
     # (2) 名称空间运行顺序
    	# 1.名称空间的加载顺序:
        	# 内置名称空间>全局名称空间>局部名称空间
        # 2.名称空间的销毁顺序:
        	# 局部空间名称>全局空间名称>内置名称空间
        # 3.名称查找的优先级:当前所在位置向上一层一层查找
        	# 如果当前在局部名称空间:
                # 局部名称空间->全局名称空间->内置名称空间
                # # input = 111
                # def func():
                #     # input = 222
                #     print(input)
                # func()
                # 运行调用函数,1.先在局部名称空间找,结果为 222,
                #             2.注释掉input = 222,局部名称空间内未找到,去全局名称空间找,结果为 111
                #             3.注释掉input =222,input = 111,局部名称空间和全局名称空间都未找到,去内置名称空间找:结果为 <built-in function input>
            # 如果当前在全局名称空间:
            	# 全局名称空间->内置名称空间 (原因参照上述分析)
        # (3).案例
        	# 示范一:
                # def func():
                #     print(x)
                # x = 222
                # func()
                # # 结果为222,x = 222为全局名称空间
                
            # 示范二:名称空间的‘嵌套空间‘关系是以函数定义阶段为准,与调用位置无关
                # x = 1
                # def func():
                #     print(x)
                # def foo():
                #     x=222
                #     func()
                # foo()
                # # 结果为1,在定义阶段x=1,
    
            # 示范三:
                # 1.从此代码到依次注释掉333,222,111, 结果为333,222,111,<built-in function input>
                # input = 111
                # def f1():
                #     input = 222
                #     def f2():
                #         input = 333
                #         print(input)
                #     f2()
                # f1()
    
                # 2.结果 222
                # input = 111
                # def f1():
                #     def f2():
                #         # input = 333
                #         print(input)
                #     input = 222
                #     f2()
                # f1()
    
            # 示范4
                # x = 111
                # def func():
                #     print(x)
                #     x = 222
                # func()
                # 报错 先定义后调用,以定义阶段为准。定义阶段:print(x),先去局部空间寻找,找到了x=222,
                # 定义阶段只要没有语法错误就不会报错,但当调用时,要输出x,但是x=222在print(x)之后,
                # 所以在x要输出时,发现未被定义,因此报错。
                
        # 二、作用域
        	# 全局作用域:内置名称空间,全局名称空间
                # 1.全局存活
                # 2.全局有效:被所有函数共享
            # 局部作用域:局部名称空间
            	# 1.局部存活
          		# 2.局部有效:函数内有效
              
    
  • global与nonlocal

    # global
        # 示范一:
            # x = 111
            # def func():
            #     x = 222
            #
            # func()
            # print(x)  # 输出结果:111
    
        # 示范二:如果在局部想修改全局名称对应的值(值为不可变类型)
        # x = 111
            # def func():
            #     global x  # 声明x这个名字是全局的名字,不需要再造新的名字了
            #     x = 222  # 将全局名称空间的x赋值成222
            # func()
            # print(x)  # 222
    
        # 示范三:
            # l = [2,3]
            # def func():
            #     l.append(4)
            #     print(l)
            # func()  # [2,3,4]
    
    # nonlocal(了解):修改函数外层的函数包含的名字对应的值(不可变类型)
        # 示范一:
            # x = 1
            # def f1():
            #     x = 2
            #     def f2():
            #         nonlocal x  # 将x = 2修改成x = 3
            #         x = 3
            #     f2()
            #     print(‘f1内的x:‘,x)
            # f1()
    
        # 如果是可变类型的话就没必要定义nonlocal了
        # 示范二:
            # x = 1
            # def f1():
            #     x = [2]
            #     def f2():
            #         x.append(3)
            #     f2()
            #     print(‘f1内的x:‘,x)  # f1内的x: [2, 3]
            # f1()
    
  • 闭包函数

    # 一、大前提
    # 闭包函数:名称空间与作用域+函数嵌套+函数对象
    #     核心点:名字的查找关系是以函数的定义阶段为标准
    
    # 什么是闭包函数:
        # ‘闭函数‘指的是该函数为内嵌函数
        # ‘包函数‘指的是该函数包含对外层函数作用域名字的引用(不是对全局作用域)
    
    # 闭包函数:名称空间与作用域+函数嵌套
         def f1():
             x = 111
             def f2():
                 x = 222
                 def f3():
                     print(x)
                 f3()
             f2()
         x = 666
         def f4():
             x = 444
             f1()
         def f5():
             x = 555
             f4()
         f5()
    
    
    # 闭包函数:函数对象
        # def f1():
        #     x = 222
        #     def f2():
        #         print(‘from f2‘, x)
        #     return f2  # 这里将f2从局部变成了全局,打破层级限制,可以在任意位置调用
        # f = f1()
        # # print(f)  # <function f1.<locals>.f2 at 0x000001A5753CC3A0>
        # def f3():
        #     x = 333
        # f()  # from f2 222
    
    # 为何要有闭包函数==》闭包函数的应用
    # 两种为函数体传参的方式
    # 方式一:直接把函数体需要的函数定义为形参
        # def func(x):
        #     print(x)
        # func(1)
        # func(2)
        # func(3)
    
    # 方式二:闭包函数
    	def outter(x):
            def wrapper():
                print(x)
            return wrapper
        wrapper = outter(111)  # 这里为其传参
        wrapper()
    
    
    # 爬网址案例
    # 需要先去cmd导入模块
    import requests
    
    ‘‘‘
    https://www.baidu.com/
    https://i.cnblogs.com/
    https://www.zhihu.com/
    ‘‘‘
    # 方案一:
    # def get(url):
    #     response = requests.get(url)
    #     print(response.text)
    # get(‘https://www.baidu.com/‘)
    # get(‘https://i.cnblogs.com/‘)
    # get(‘https://www.zhihu.com/‘)
    
    # 方案二:
    # def website(url):
    #     def get():
    #         response = requests.get(url)
    #         print(response.text)
    #     return get
    # baidu = website(‘https://www.baidu.com/‘)
    # baidu()
    #
    # cnblogs = website(‘https://i.cnblogs.com/‘)
    # cnblogs()
    #
    # zhihu = website(‘https://www.zhihu.com/‘)
    # zhihu()
    

闭包函数=函数对象+函数嵌套+名称空间与作用域

上一篇:函数名称空间与作用域


下一篇:Qt编写自定义控件及插件的使用