Python-命名空间和变量作用域详解(global、nonlocal)

目录

上篇文章思考题

命名空间

作用域

全局变量与局部变量

就近原则

只读问题

关键字

全部代码

总结

思考题


上篇文章思考题

Python-函数基础总结与内置函数

1.

def plus(*args):
    return sum(args)
 
 
print(plus(1, 2, 3))
print(plus(2, 4, 6, 8, 10))

结果:

6

30

2.

def power(x=2, n):
    return x ** n

结果:

    def power(x=2, n):
             ^
SyntaxError: non-default argument follows default argument

注意:有默认值的参数必须在无默认值参数的后面

可写为:

def power(n, x=2):
    return x ** n

对于包含 参数有默认值的 函数,而且已经调用了,不易改动,不方便添加不含默认值的参数,保证健壮性,只能添加默认值。

power(x,n=2)添加y参数时power(x,n=2,y)是不对的,只能是power(x,n=2,y=None),y可以赋值为其他默认值。

命名空间

命名空间(namespace )是一个从名字到对象的映射,当前,大部分命名空间都由 Python 字典实现。

同命名空间中的名称之间绝对没有关系,例如,两个不同的模块都可以定义一个 maximize 函数而不会产生混淆,当然,模块的用户必须在其前面加上模块名称。类似一个文件夹内不能有重复名称的文件,但是,不同的文件夹内可以有相同名称的文件。

在不同时刻创建的命名空间拥有不同的生存期。包含内置名称的命名空间是在 Python 解释器启动时创建的,永远不会被删除。

模块的全局命名空间在模块定义被读入时创建,通常,模块命名空间也会持续到解释器退出。

作用域

一个 作用域 是一个命名空间可直接访问的 Python 程序的文本区域。 这里的 “可直接访问” 意味着对名称的非限定引用(非限定引用就是你没加关键字,Python默认情况下)会尝试在命名空间中查找名称

  • L(Local):最内层,包含局部变量,比如一个函数/方法内部。
  • E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。
  • G(Global):当前脚本的最外层,比如当前模块的全局变量。
  • B(Built-in): 包含了内建的变量/关键字等。

搜索顺序:L –> E –> G –>B

接下来我们就不说B了,随时都能访问,应该没有什么疑惑。

全局变量与局部变量

我们定义一个全局变量name,Show函数中定义一个局部变量name。

name = 'lady_killer'


def Show():
    university = 'BUPT'

    def show_nonlocal():
        print('show_nonlocal:', university)
        print('show_nonlocal:', name)

    def show_global():
        print('show_global:', university)
        print('show_global:', name)

    show_nonlocal()
    show_global()
    print('local:', university)


# NameError: name 'university' is not defined
# print(university)
Show()
print('gloabal:', name)

结果:

show_nonlocal: BUPT
show_nonlocal: lady_killer
show_global: BUPT
show_global: lady_killer
local: BUPT
gloabal: lady_killer

当然,局部作用域外不能访问局部变量

Traceback (most recent call last):
  File "learnarea.py", line 28, in <module>
    print(university)
NameError: name 'university' is not defined

就近原则

接下来我们就看看同名的情况。

我们对show函数进行一下修改,在局部作用域增加同名的变量。

def Show():
    university = 'BUPT'
    name = 'YuBo'

    def show_nonlocal():
        university = 'bupt'
        name = 'frankyu'
        print('show_nonlocal:', university)
        print('show_nonlocal:', name)

    def show_global():
        print('show_global:', university)
        print('show_global:', name)

    show_nonlocal()
    show_global()
    print('local:', university)

结果:

show_nonlocal: bupt
show_nonlocal: frankyu
show_global: BUPT
show_global: YuBo
local: BUPT
gloabal: lady_killer

可以看到按照L->E->G顺序查找,即就近原则

只读问题

我们尝试增加一个全局变量num,并在函数内进行复合的赋值操作,关于操作符可查看Python-操作符总结(逻辑、位、算术、比较、赋值操作符及操作符优先级)

num = 1


def Show():
    university = 'BUPT'
    name = 'YuBo'
    # UnboundLocalError: local variable 'num' referenced before assignment
    num += 1

结果:

Traceback (most recent call last):
  File "learnarea.py", line 35, in <module>
    Show()
  File "learnarea.py", line 16, in Show
    num += 1
UnboundLocalError: local variable 'num' referenced before assignment

num += 1,即 num = num + 1,在找后面的num时没有去全局变量寻找,而是认为局部变量,但是我们没有定义局部变量num,所以就是赋值前引用,如果我们在num+=1前使用num=2之类的进行定义num,就不会出错了,但如果我们想使用全局变量该怎么办呢?请继续看。

关键字

global关键字用于使用全局变量

nonlocal关键字用于使用嵌套外部函数变量

def Show():
    university = 'BUPT'
    global name
    name += 'YuBo'

    # UnboundLocalError: local variable 'num' referenced before assignment
    # num += 1
    def show_nonlocal():
        nonlocal university
        university += 'bupt'
        name = 'frankyu'
        print('show_nonlocal:', university)
        print('show_nonlocal:', name)

    def show_global():
        print('show_global:', university)
        print('show_global:', name)

结果:

show_nonlocal: BUPTbupt
show_nonlocal: frankyu
show_global: BUPTbupt
show_global: lady_killerYuBo
local: BUPTbupt
gloabal: lady_killerYuBo

全部代码

"""
--coding:utf-8--
@File: learnarea.py
@Author:frank yu
@DateTime: 2020.10.23 15:00
@Contact: frankyu112058@gmail.com
@Description: 学习变量作用域
"""
name = 'lady_killer'
num = 1


def Show():
    university = 'BUPT'
    global name
    name += 'YuBo'

    # UnboundLocalError: local variable 'num' referenced before assignment
    # num += 1
    def show_nonlocal():
        nonlocal university
        university += 'bupt'
        name = 'frankyu'
        print('show_nonlocal:', university)
        print('show_nonlocal:', name)

    def show_global():
        print('show_global:', university)
        print('show_global:', name)

    show_nonlocal()
    show_global()
    print('local:', university)


# NameError: name 'university' is not defined
# print(university)
Show()
print('gloabal:', name)

总结

  • 局部作用域外不能访问局部变量
  • 非限定引用下,按照L->E->G顺序查找,即就近原则
  • 非限定引用下,无法在局部对全局变量进行修改
  • 如果要修改局部外的变量,可以使用global、nonlocal分别对全局变量和嵌套外部函数的变量进行修改
  • 建议不在局部使用和外部相同的变量名称

思考题

以下代码。结果是什么?

send_packet = 56


def test(i):
    global send_packet
    if i > 5:
        send_packet = 1
    return send_packet


print(test(2))
print(test(6))

如果是这样呢?

send_packet = 56


def test(i):
    global send_packet
    if i > 5:
        send_packet = 1
    return send_packet


print(test(6))
print(test(2))

答案见:Python-面向对象编程总结(类、对象、派生、继承、方法、内置函数等)

更多python相关内容:【python总结】python学习框架梳理

本人b站账号:lady_killer9

有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。如果您感觉有所收获,自愿打赏,可选择支付宝18833895206(小于),您的支持是我不断更新的动力。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lady_killer9

感谢您的打赏,我会加倍努力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值