zoukankan      html  css  js  c++  java
  • day10 -- 函数对象、函数名称空间和作用域

    目  录

        函数名称空间和查找顺序练习题(重点:待更新)

     

    一、函数对象

    函数对像是第一类对象:函数名所指向的值可以被当做参数进行传递。

    1、函数名可以被当做参数进行传递,进行赋值

    # 函数对象
    def func():
        print('函数对象可以被赋值!')
    func()  #
    f = func  # 函数进行赋值的时候一定要是函数名赋值,千万不能加括号,函数名+括号就是函数的调用
    f()  # 函数对象可以被赋值 -- f其实指向的也就是桉树func指向的函数体代码块的内存地址

    2、函数名可以传递给其他函数传参

    # 作为其他函数的参数
    def func():
        print('第一参数')
    
    def func2(x):
        print(x)  # <function func at 0x02CC4810> 函数名func指向的函数体的内存地址
        func()  # 第一参数
        print('第二参数')  # 第二参数
    func2(func)

    3、函数名可以作为函数的返回值

    # 3.函数名可以被当做函数的返回值
    def index():
        print('index')
    
    def func():
        print('func')
        return index
    res = func()  # 结果res = index
    print(res)  # 打印函数名index所指向的函数体代码块的内存地址
    res()  # index函数调用

    执行书序图解:

    4、函数可以作为其他容器类型里面的元素

    # 循环打印项目功能提示信息 供用户选择 用户选择谁就执行谁
    def register():
        username = input('username>>>:').strip()
        pwd = input('password>>>:').strip()
        print(username,pwd)
        print('register ...')
    def login():
        print('login ...')
    def transfer():
        print('transfer ...')
    def shopping():
        print('shopping...')
    def pay():
        print('pay ...')
    
    msg = """
    1 注册
    2 登陆
    3 转账
    4 购物
    5 支付
    """
    func_dict = {
        '1':register,
        '2':login,
        '3':transfer,
        '4':shopping,
        '5':pay,
    }
    while True:
        print(msg)
        choice = input('请现在你想要执行的功能>>>:').strip()
        if choice in func_dict:
            func_dict.get(choice)()  # 函数名()
    
        # if choice == '1':
        #     register()
        # elif choice == '2':
        #     login()
        # elif choice == '3':
        #     transfer()
        # elif choice == '4':
        #     shopping()
        # elif choice == '5':
        #     pay()
        else:
            print('你输入的功能暂时没有')
    将各个功能函数作为字典的value调用

    二、函数的嵌套

    函数的嵌套分为嵌套调用和嵌套定义。

    1、函数的嵌套调用:顾名思义是在函数体内调用其他函数

    def my_max(x,y):
        if x > y:
            return x
        return y
    
    def my_max4(a,b,c,d):
        res1 = my_max(a,b)
        res2 = my_max(res1,c)
        res3 = my_max(res2,d)
        return res3
    print(my_max4(1,2,10,4))
    View Code

    2、函数的嵌套定义:在函数内定义函数

    应用场景:在一个函数内通过传不同的参数来实现不同的功能。

    def outer():
        x = 1
        print('outer')
        def inner():
            print('inner')
        # print(inner)
        return inner
    
    res = outer()  # outer()首先print('outer'),再将inner赋值给res,即res指向函数名inner指向的函数体代码所在的内存地址
    print(res)  # 打印inner所指向函数体代码的内存地址
    res() # 将inner赋值给res,并调用
    View Code

    程序实行结果如图:

    三、函数的名称空间

    名称空间:通俗解释就是存放名字的地方。

    详细解释:名称空间是存放变量名和变量值的内存地址绑定关系的地方。我们想要访问一个变量,首先要去名称空间找到变量名,才能找到对应的变量值。

    名称空间的分类:

    1、内置名称空间:python解释器字典的方法,已经写在内置名称空间里了  len() max() min()...

    2、全局名称空间:文件级的代码

    x = 1
    
    if 1 ==1 :
        y = 2
                    
         print(y)
          while True:
                   z = 3
                     
     x,y,z都会放到全局名称空间
     if for while 无论嵌套多少层 它们内部所创建的名字都是全局名称空间的

    3、局部名称空间:函数内部定义的变量名都属于局部名称空间  例如:username

    四、名称空间的查找顺序

    名字空间的查找顺序(******)

    名字查找顺序如下图所示:

      首先要确定你当前的位置(大前提)

        1、站在全局       全局  》》》 内置

        2、站在局部       局部  》》》 全局 》》》 内置

    注意函数在定义阶段名字的查找顺序就已经确定了,不会因为函数调用位置的变化而变化。*******

    函数名称空间和查找顺序练习题(重点:待更新)

    1、第一个坑点:

    # ----第一个错题
    
    def index():
        x = 'xxx'
    
    def index2():
        print(x)
        y = 666
    
    index()  # 执行完该步骤后定义 x = 'xxx'
    index2()  # 报错!NameError: name 'x' is not defined 局部名称空间无法调用另一个局部名称空间的值

    2、第二个坑点

    x = 111
    def f1():
        x = 222
        def f2():
            x = 333
            def f3():
                x = 444
                def f4():  # 到这一步,先定义函数f4
                    # x = 555
                    print(x)  # 第4步执行 函数f4代码块。此时在函数f4的名称空间内寻找,找到在    
                                    第二步已经定义的x并打印出x的值
                x = 6969   # 第二步:x赋值6969
                f4()  # 第三步调用函数f4
            f3()
        f2()
    f1()  # 结果:6969    

    3、第三个坑点:

    x = 111
    def f1():
        x = 222
        def f2():
            x = 333
            def f3():
                # x = 444
                def f4():
                    # x = 555
                    print(x)
                f4()  # 错误原因:在函数f4开始调用之后,函数体代码开始运行,但是x=6969还没 
                           有执行
                x = 6969
            f3()
        f2()
    f1()  # 结果:报错,x在没有定义前就调用了

    4、第4个坑点:

    def func():
        # x = 1
        def index():
            print(x)  # 获取全局找x
        return index
    
    res = func()
    x = 999
    res()  # 结果:999

    反例:与第三个坑点相同

    # 反例
    def func():
        # x = 1
        def index():
            print(x)  # 获取全局找x
        return index
    
    res = func()
    res()  # 结果:报错,x还没有定义
    x = 999

    5、第5个坑点:

    # 名字查找练习
    x = 111
    def outer():
        def inner():
            print("from index",x)
        return inner
    f = outer()  # 将函数名inner赋值给f,即f=inner
    x = 222  # x=222覆盖住 x=111
    f()  # 结果:from index 222

    检测题:要深刻理解“函数在定义阶段名字的查找顺序就已经确定了”这句话

    # 名字查找练习
    x = 111
    def outer():
        def inner():
            print("from index",x)  # x的值已经确定在全局找
        return inner
    f = outer()
    def func():
        x = 333  # x 已经确定在全局名称空间中找,所以不会去函数func中去找
        f()
    func()  # 结果:from index 111

    五、函数作用域

    函数作用域分为全局作用域局部作用域

    全局作用域:全局有效,主要指内置名称空间,全局名称空间。

    局部作用域:局部有效,主要指局部名称空间。

    两个关键字:global关键字 和nonlocal关键字

    """
    global:局部修改全局 如果想修改多个 逗号隔开
    nonlocal:局部修局部 如果想修改多个 逗号隔开
    
    """
    # global 在局部修改全局的不可变数据类型
    # x = []  # 因为列表是可变类型
    x = 1  # 不可变类型
    username = 'jason'
    def func():
        # x.append('嘿嘿嘿')
        global x,username  # 修改全局变量 而不是创建局部名称空间
        x = 999
        username = 'egon'
    func()
    print(x)
    print(username)
    global关键字改变全局变量
    # nonlocal  局部修改局部
    def func():
        x = 1
        def index():
            nonlocal x
            x = 2
        index()
        print(x)
    func()
    nonlocal关键字改变局部变量
  • 相关阅读:
    spingboot集成jpa(二)
    datanode与namenode的通信
    Yarn NodeManager restart
    hadoop上线和下线节点
    Spark读取文件
    eclipse安装中文补丁包
    eclipse中maven打包
    (转) eclipse安装lombok
    Windows 访问 Oracle
    wCF 问题收集页
  • 原文地址:https://www.cnblogs.com/qinsungui921112/p/11164445.html
Copyright © 2011-2022 走看看