代码改变世界

day10 -- 函数对象、函数名称空间和作用域

2019-07-10 15:49  在上海的日子里  阅读(221)  评论(0编辑  收藏  举报

目  录

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

 

 

一、函数对象

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

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关键字改变局部变量