[ python ] 函数进阶

 命名空间

从 python 解释器开始执行之后,就在内存中开辟了一个空间,每当遇到一个变量的时候,就把变量名和值之间的对应关系记录下来。但是 当遇到函数定义的时候解释器只是象征性的将函数名读入内存,表示知道这个函数的存在了,至于函数内部的变量和逻辑解释器根本不关心。等执行到函数调用的时候,python解释器会再开辟一块内存来存储这个函数里的内容,这个时候,才关注函数里面有哪些变量,而函数中的变量会存储在新开辟出来的内存中。

函数中的变量只能在函数的内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被清空。

我们给这个‘存放名字与值的关系’的空间起了一个名字————叫做命名空间

代码在运行伊始,创建的存储‘变量名与值的关系’的空间叫做 全局命名空间,在函数的运行中开辟的临时的空间叫做 局部命名空间。

命名空间的本质:存放名字与值的绑定关系

 

命名空间有三种:
    内置命名空间
        内置命名空间中存放了python解释器为我们提供的名字:input,print,str,list,tuple...它们都是我们熟悉的,拿过来就可以用的方法。
    全局命名空间
        在python文件中,顶头命名的变量名字,都包含在全局命名空间中
    局部命名空间
        函数和类中的都在局部命名空间中,且每个局部命名空间是相互独立的

 

三种命名空间之间的加载与取值顺序:
    加载顺序:内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)
    取值:
        在局部调用:局部命名空间->全局命名空间->内置命名空间。必须遵守从内向外找,直到内置空间中如果也没有,则报错;

 

 

作用域

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

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

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

 

globals 和 locals 使用方法

复制代码
print(globals())    # 打印全局命名空间中的变量
print(locals())        # 在全局中打印全局命名空间中的变量,在局部打印局部命名空间中的变量

print(globals() == locals())     # 当 globals() 和 locals() 都在全局作用域中,打印的结果一样

# 执行结果:
# ......
# True
使用说明1
复制代码
复制代码
def func():
    a = 1
    print(globals())    # 打印全局命名空间中的变量
    print(locals())        # 只会打印局部命名空间中的变量,{'a': 1}

    
func()


global 关键字的使用

a = 10

def func():
    global a    # 获取全局空间中的变量
    a = 20      # 修改变量a

print(a)    # 打印全局变量中的a
func()
print(a)    # 打印修改后的变量a

# 执行结果:
# 10
# 20
使用说明2
复制代码

 

 

函数的嵌套和作用域链

 

复制代码
def f1():
    print('in f1')
    def f2():
        print('in f2')
    f2()

f1()

# 执行结果:
# in f1
# in f2
函数嵌套实例1
复制代码

 

函数运行流程:

 

复制代码
def f1():
    def f2():
        def f3():
            print('in f3')
        print('in f2')
        f3()

    print('in f1')
    f2()

f1()

# 执行结果:
# in f1
# in f2
# in f3
嵌套函数实例2
复制代码

 

 

函数运行流程:

 

 

函数的作用域链

 

复制代码
def f1():
    a = 1
    def f2():
        print(a)

    f2()

f1()
实例1
复制代码

 

函数运行流程:

 

复制代码
def f1():
    a = 1
    def f2():
        def f3():
            print(a)

        f3()
    f2()

f1()

# 执行结果:
# 1
实例2
复制代码

 

 

函数运行流程:

 

 

nolocal 关键字

    1. 外部必须有这个变量
    2. 在内部函数声明 nonlocal 变量之前不能再出现同名变量
    3. 内部修改这个变量如果想在外部有这个变量的第一层函数中生效

 

复制代码
def f1():
    a = 1
    def f2():
        nonlocal a
        a = 2

    f2()
    print('a in f1:', a)

f1()

# 运行结果:
# a in f1: 2
实例1
复制代码

 

函数运行流程:

 

函数的本质
    在python中一切皆对象,函数名本质上就是函数的内存地址

 

    1. 可以被引用

1
2
3
4
5
6
7
8
def func():
    print('hello world')
 
f = func
f()
 
# 执行结果:
# hello world  

 

    2. 可以被当作容器类型的元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def f1():
    print('func: f1')
 
def f2():
    print('func: f2')
 
def f3():
    print('func: f3')
 
l = [f1, f2, f3]
 
for i in l:
    i()
 
# 执行结果:
# func: f1
# func: f2
# func: f3

 

    3. 可以当作函数的参数和返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
def f():
    print('func: f')
 
def func(f):
    print('func: func')
    return f
 
c = func(f)
c()
 
# 执行结果:
# func: func
# func: f

 

函数运行流程:

 

闭包

闭包函数包含对外部作用域而非全局作用域名字的引用,该内部函数称为闭包函数。
闭包必须满足以下两点:
    1. 嵌套函数:定义在内部的函数无法直接在全局被调用
    2. 内部函数调用外部函数的变量

 

一个闭包函数最常用的用法:

1
2
3
4
5
6
7
8
9
10
11
def func():
    name = 'xiaofei'
    def inner():
        print(name)
    return inner
 
f = func()
f()
 
# 执行结果:
# xiaofei

 

函数运行流程:

 

 

练习题:

请编写代码通过如下测试结果:

1
2
3
4
5
6
7
8
# 测试:
counterA = createCounter()
print(counterA(), counterA(), counterA(), counterA(), counterA()) # 1 2 3 4 5
counterB = createCounter()
if [counterB(), counterB(), counterB(), counterB()] == [1, 2, 3, 4]:
    print('测试通过!')
else:
    print('测试失败!')

 

复制代码
def createCounter():
    n = 0
    def counter():
        nonlocal n        # nonlocal关键字是获取局部变量n
        n += 1            # 修改局部变量 n
        return n
    return counter
练习题答案
复制代码

 

本文作者:hukey

本文链接:https://www.cnblogs.com/hukey/p/9681862.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   hukey  阅读(289)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 彩虹 Jay
彩虹 - Jay
00:00 / 00:00
An audio error has occurred.

彩虹 + 轨迹 (Live) - 周杰伦 (Jay Chou)

彩虹

词:周杰伦

曲:周杰伦

哪里有彩虹告诉我

哪里有彩虹告诉我

能不能把我的愿望还给我

能不能把我的愿望还给我

为什么天这么安静

为什么天这么安静

所有的云都跑到我这里

有没有口罩一个给我

有没有口罩一个给我

释怀说了太多就成真不了

释怀说了太多就成真不了

也许时间是一种解药

也许时间是一种解药

也是我现在正服下的毒药

也是我现在正服下的毒药

看不见你的笑 我怎么睡得着

看不见你的笑 我怎么睡得着

你的声音这么近我却抱不到

你的声音这么近我却抱不到

没有地球太阳还是会绕

没有地球太阳还是会绕

没有理由我也能自己走

没有理由我也能自己走

你要离开 我知道很简单

你要离开 我知道很简单

你说依赖 是我们的阻碍

你说依赖 是我们的阻碍

就算放开 但能不能别没收我的爱

就算放开 但能不能别没收我的爱

当作我最后才明白

当作我最后才明白

看不见你的笑 要我怎么睡得着

看不见你的笑 要我怎么睡得着

你的声音这么近我却抱不到

没有地球太阳还是会绕 会绕

没有理由我也能自己走掉

释怀说了太多就成真不了

也许时间是一种解药 解药

也是我现在正服下的毒药

轨迹

词:黄俊郎

曲:周杰伦

我会发着呆然后忘记你

接着紧紧闭上眼

想着哪一天 会有人代替

想着哪一天 会有人代替

让我不再想念你

我会发着呆 然后微微笑

我会发着呆 然后微微笑

接着紧紧闭上眼

又想了一遍 你温柔的脸

又想了一遍 你温柔的脸

在我忘记之前