zoukankan      html  css  js  c++  java
  • Python基础之(函数进阶)

    一、命名空间和作用域

    1.1、命名空间

    先来看个例子:

    a=123
    def test(a):
        m=321
        print(a) #不报错
    
    print(m) #报错了

    上面为什么会报错呢?现在我们来分析一下python内部的原理是怎么样:

      我们首先回忆一下Python代码运行的时候遇到函数是怎么做的,从Python解释器开始执行之后,就在内存中开辟出一个空间,每当遇到一个变量的时候,就把变量名和值之间对应的关系记录下来,但是当遇到函数定义的时候,解释器只是象征性的将函数名读入内存,表示知道这个函数存在了,至于函数内部的变量和逻辑,解释器根本不关心。等执行到函数调用的时候,Python解释器会再开辟一块内存来储存这个函数里面的内容,这个时候,才关注函数里面有哪些变量,而函数中的变量会储存在新开辟出来的内存中,函数中的变量只能在函数内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被清空。

    我们给这个‘存放名字与值的关系’的空间起了一个名字-------命名空间。代码在运行伊始,创建的存储“变量名与值的关系”的空间叫做全局命名空间;在函数的运行中开辟的临时的空间叫做局部命名空间。

      命名空间一共可以分为三种:全局命名空间、局部命名空间、内置命名空间

      (ps:内置命名空间中存放了python解释器为我们提供的名字:input,print,str,list,tuple...它们都是我们熟悉的,拿过来就可以用的方法)

    三种命名空间之间的加载与取值顺序:

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

    取值顺序:

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

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

    综上所述,在找寻变量时,从小范围,一层一层到大范围去找寻。由此可见例子中的a=123为全局变量,当在函数中调用的时候是没有问题的,而m=321为局部变量,在全局中进行打印的时候就会报错,找不到m值

    1.2、作用域

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

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

    局部作用域:局部名称空间,只能在局部范围内生效

    globals和locals方法(查看全局和局部命名空间)

    ps:globals和locals都在全局的时候两者一样,当两者都处于局部的时候globals为全局,locals为局部

    print(globals())
    print(locals())   #全局
    
    def func():
        a = 12
        b = 20
        print(locals())
        print(globals())  #局部
    
    func()

    global关键字

    • 声明一个全局变量
    • 在局部作用域想要对全局作用域的全局变量进行修改时,需要用到 global(限于字符串,数字)。
    a=1
    def fun():
        global a
        a=2
    fun()
    print(a)

    执行结果:

    ps:对可变数据类型(list,dict,set)可以直接引用不用通过global

    li=[1,2,3]
    di={"a":1,"b":2}
    def fun():
        li.append(4)
        di["c"]=3
    fun()
    print(li,di)
    

    执行结果:

    nonlocal 关键字 (python3中)

    适用于嵌套函数中内部函数修改外部变量的值(上一层)

    def fun():
        a = 2
        def fun2():
            nonlocal a
            a = a + 20
            print(a)
        fun2()
        print(a)
    fun()
    

    执行结果:

    二、函数的嵌套和作用域链

    2.1、函数的嵌套调用

    def fun(a,b):
        if a>b:
            v=a
        else:
            v=b
        return v
    def fun1(x,y,z):
        v=fun(x,y)
        v1=fun(v,z)
        return v1
    print(fun1(2,-1,5))
    
    #结果为:5
    

    2.2、函数的嵌套定义

    def fun():
        def fun1():
            print("in the fun1")
        fun1()      #此处对fun1进行调用,如不调用即是在fun中定义了一个fun1的函数
    fun()
    

    2.3、作用域链

    函数的作用域链:小范围作用域可以使用大范围的变量,(只是查看,如果需要修改全局的使用global,局部上层使用nonlocal)但是反之不行,他是单向的。(针对不可变数据类型)

    三、函数名本质

    函数名本质上就是内存地址

    3.1、函数名可以被引用

    def func():
        print('in func')
    
    f = func
    print(f)

    3.2、函数名可以被当作容器类型的元素

    def f1():
        print('f1')
    def f2():
        print('f2')
    d = {'f1':f1,'f2':f2}
    d["f1"]()  #调用 

    3.3、函数名可以当作函数的参数和返回值

    def f1():
        print('f1')
    
    def func1(argv):
        argv()
        return argv
    
    f = func1(f1)
    f()

    一句话:函数是第一类对象,即函数可以当作数据传递 (不明白?那就把函数当变量用)

    四、闭包函数

    内部函数包含对外部作用域而非全局作用域变量的引用,该内部函数称为闭包函数

    def fun():
        a=123
        def inner():
            print(a)
    

    由于有了作用域的关系,我们就不能拿到函数内部的变量和函数了。如果我们就是想拿怎么办呢?返回呀!(这才是闭包函数的常用方法)

    def fun():
        a=123
        def inner():
            print(a)
        return inner
    
    f=fun()
    f()  #调用返回的inner函数的内存地址
    

     闭包函数的例子:

    from urllib.request import urlopen
    
    def fun(url):
        def get():
            return urlopen(url).read()
        return get
    
    sina=fun('http://www.sina.cn')
    print(sina().decode()) #sina首页的源码

    判断是否是闭包函数:__closure__

    def fun():
        a=123
        def inner():
            print(a)
    
        print(inner.__closure__)
    
    fun()
    print(fun.__closure__)

     执行结果:

  • 相关阅读:
    Xcode安装Cocos2d-iphone
    Java最重要的21个技术点和知识点之JAVA基础
    Java最重要的21个技术点和知识点之JAVA面向对象
    Java最重要的21个技术点和知识点之JAVA集合框架、异常类、IO
    Java最重要的21个技术点和知识点之JAVA多线程、时间处理、数据格式
    Java最重要的21个技术点和知识点
    Linux 条件变量
    getcwd
    struct stat结构体简介
    SSL 程序设计初步介绍
  • 原文地址:https://www.cnblogs.com/crazyjump/p/10059264.html
Copyright © 2011-2022 走看看