zoukankan      html  css  js  c++  java
  • 20181128(闭包函数,函数嵌套,名称空间,作用域)

    一、函数对象:把函数的内存地址当成一种变量值去使用

    在面向对象的编程中 一切皆对象

    函数func()

    fun是函数func()的内存地址
    函数的的内存地址加上括号就会触发代码的运行。
    def func():  #定义了一个函数func()
       print('666')
    func()  #执行该函数,输出结果为666
    print(func) #输出结果为:<function func at 0x00000236A9432E18>,即内存地址
    print(func())  #输出结果为666和None,输出666是因执行了函数的操作,输出None是因为函数没有设定返回值,所以默认是None,注意和下面的对比。
    func=111
    print(func)  #输出结果为111
    func()  #报错,调用一个不能被调用的变量或对象,具体表现就是你调用函数、变量的方式错误。
    print(func())   #报错,理由同上

    如果:
    def func():
       return 123
    print(func())
    输出结果为:
    123

     

    具体的体现:

    1.函数可以被引用

    def bar():
       print('from bar')

    f=bar
    f()
    输出结果为:
    from bar

    2.函数可以作为函数的参数

    def bar():
       print('from bar')

    def wrapper(func): #func=bar
       func() #bar()

    wrapper(bar)
    输出结果为:
    from bar

     

    3.函数可以作为函数的返回值

    def bar():
       print('from bar')

    def foo(func):
       return func

    f=foo(bar) #先执行这一句,得出f=bar
    f()  #等同于bar()
    输出结果为:
    from bar

     

    4.可以被存储到容器类型中

    def get():
       print('from get')

    def put():
       print('from put')

    l=[get,put]
    l[0]()
    输出结果为;
    from get

    #写一个购物车,要求注册登录

     

    二、函数嵌套

    1.嵌套调用:在一个函数中调用了另一个函数

    def max2(x,y):
       if x > y:
           return x
       else:
           return y

    def max3(x,y,z):
       res1=max2(x,y)  #因为max2函数有返回值,所以可以有等于
       res2=max2(res1,z)
       return res2  #等同于返回最大值

    print(max3(11,199,2))
    输出结果为:
    199

     

    2.嵌套定义:在一个函数中,又定义了另一个函数。定义在函数内的函数,只能在函数内使用,外界不能访问。

    def func1():
       print('from func1')
       def func2():
           print('from func2')
       func2()  #调用func2()函数
       print(func2)    #输出其内存地址,观察输出结果为(所在功能块,变量所在空间(局部变量?全局变量?),内存地址)
    func1()
    输出结果:
    from func1
    from func2
    <function func1.<locals>.func2 at 0x00000207784F9B70>  


    def func1():
       print('from func1')
       def func2():
           print('from func2')
       func2()  
       print(func2)  
    func1()
    print(func2())  #此处会报错,因为定义在函数内的函数,只能在函数内使用,外界不能访问。

    3.函数的嵌套中:nonlocal a #声明使用上一层的变量a,如果上一层没有则找上上一层,但是不能寻找全局变量。嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量。

    a = 1
    b = 2
    def func1():
       a = 10
       def func2():
           b = 20
           def func3():
               nonlocal a,b
               print(a,b)
           func3()
       func2()
    func1()
    print(a,b)
    输出结果为:
    10 20
    1 2
    a = 1
    b = 2
    def func1():
       a = 10
       def func2():
           def func3():
               nonlocal a,b
               print(a,b)  #此处的b只能取函数内变量的值,不能取全局变量的值,因为上一句已经申明a,b只能修改获取嵌套作用域内的变量。
           func3()
       func2()
    func1()
    输出结果会报错

    如果修改为:
    a = 1
    b = 2
    def func1():
       a = 10
       def func2():
           def func3():
               nonlocal a
               print(a,b)  #此时b可以取全局变量
           func3()
       func2()
    func1()
    输出结果为:
    10 2

     

    三、名称空间:又名name space,是存放变量名和值绑定关系的地方。

    名称空间分为三类:

    builtins:内置名称空间,存储解释器自带的一些名称与值的对应关系(解释器启动时创建,关闭解释器时销毁)

    globals:全局名称空间,又名模块名称空间,在模块内定义的名称(文件级别的名字),除了内置的和函数内的,都在全局中。(执行py文件时创建全局名称空间,在文件结束或者文件执行期间被删除则失效。)

    locals:局部名称空间,只要是函数内的名称就是局部的,包括局部变量和形参(函数调用时创建,函数执行完毕后销毁)

    不同变量的作用域不同就是由于这个变量所在的名称空间决定的。

    加载顺序:

    内置名称空间---》全局名称空间----》局部名称空间

    查找顺序:

    局部名称空间 ---》全局名称空间----》内置名称空间(不完全对)
    查找名字的顺序是从当前位置往外查找
    名称空间的嵌套关系是在函数定义阶段就固定死的,与调用位置无关。

    细分之下有四种空间:

    locals 函数内的名字空间,包括局部变量和形参
    enclosing 外部嵌套函数的名字空间
    globals 全局变量,函数定义所在模块的名字空间
    builtins 内置模块的名字空间
    查找顺序为LEGB,即
    locals-->enclosing function-->globals-->_builtins_

     

    四、作用域

    域:指的是区域、范围的意思

    python中有两种最基本的变量作用域:

    局部变量:

    1.只能在函数内使用

    2.调用函数时生效,调用结束失效

    全局变量:

    1.在任何位置都能访问到

    2.该范围内的名字会伴随程序的整个生命周期

     

    局部变量:在函数内定义的变量名只能在函数内部引用,不能在函数外引用,这个变量的作用域是局部的,也称为局部变量。一般来说,定义的变量如果是在函数体中第一次出现,就是局部变量。

    x = 50
    def func(x):
       print(x)
       x = 2
       print(x)
    func(x)
    print(x)
    输出结果:   # 调用func()时创建了新的命名空间,作用于func的代码块
    50
    2
    50

     

    全局变量:在函数体外,一段代码最开始赋值的变量可以被多个函数引用,这就是全局变量。全局变量可以在整个程序范围内被引用。

    num = 100
    def func():
       num = 200
       print(num)
    func()
    print(num)
    输出结果:  #函数中使用某个变量时,如果该变量名既有全局变量又有局部变量,就默认使用局部变量。在函数体中更改全局变量的值不会影响全局变量在其他函数或语句中的使用。
    200
    100

    如何将局部变量变更为全局变量:

    num = 100
    print(num)
    def func():
       global num  #在函数体中的变量前加关键字 global,函数调用结束后,在函数体外使用变量时,值变得和函数体中的值一样
       num = 200
       num += 100
       print(num)

    func()
    print(num)
    输出结果:
    100
    300
    300

     

    globals() 查看全局作用域的内容

    locals() 查看局部作用域的内容

    五、闭包函数

    闭包函数是一种函数,其中:

    闭:指的是定义在函数内部的函数;

    包:指的是该函数内包含对外层函数作用域名字的引用。

     

    函数的作用域在定义的时候就固定了,与调用的位置没有关系。

     

    闭包的定义:如果在一个内部函数里对外部函数(不是在全局作用域)的变量进行引用,内部函数就认为是闭包。

    闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得该函数无论在何处调用,都优先使用自己外层包裹的作用域。

    什么是闭包函数

    ①定义在另一个函数中的函数

    ②内部的函数中访问了外部的名称(不包含全局的数据)

     

    与普通函数的区别

    ①定义在另一个函数中的

    ②在内部的函数中使用了外部的名称

    def s(*args):
       def c():
           a=0
           for n in args:
               a=a+n
           return a
       return c
    print(s(1,2,3,4))
    c=s(1,2,3,4)
    print(c())
    输出结果为:
    <function s.<locals>.c at 0x000001F3D3469B70>
    10

     

    在返回内部函数时,不是单纯的返回函数,还把函数中访问到的局部变量名称一起打包了

     

    闭包函数的模板:

    def func1():

    a = 1

    def innner():

    print(a)

    return inner

    func1()

    x=10
    def f():
       print(x)
    f()


    def outer():
       x=11
       def f():
           print(x)
       f()   #调用outer()时,也会直接调用f()
    outer()  

    def outer(x):
       def f():
           print(x)
       return f
    fff=outer(666)
    fff()
    输出结果为:
    10
    11
    666


    def x(x):
       def y():
           def z():
               print(x)
           return z
       return y
    y=x(10)  #返回三层
    z=y()
    z()
    输出结果为:
    10



    def x():
       def y(x):
           def z():
               print(x)
           return z
       return y
    y=x()
    z=y(1111)
    z()
    输出结果为:
    1111

     

     

     

     

  • 相关阅读:
    thinkphp 学习1-模型
    apache 2.4目录权限
    标头 header()函数的用法
    PHP面试题一
    php学习
    如何执行超过一百兆(100MB)的sql脚本?
    jquery-numberformatter插件
    xpath 获取父级,和同级
    Vue el-table 行编辑验证、重置
    Vue 弹窗一个新增编辑页面
  • 原文地址:https://www.cnblogs.com/realadmin/p/10036040.html
Copyright © 2011-2022 走看看