V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
jurassic2long
V2EX  ›  Python

请教各位大佬一个 Python 问题,关于局部变量。

  •  
  •   jurassic2long · 2023-03-20 22:29:12 +08:00 · 1569 次点击
    这是一个创建于 374 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如图,第三个函数中,全局变量 a 为何被当做局部变量了,与前两个函数有什么不一样?
    (第一次发图不知道能不能显示出来,多写一种格式试试)
    https://imgur.com/SJzAH2m

    11 条回复    2023-03-21 12:55:05 +08:00
    f1ush
        1
    f1ush  
       2023-03-20 22:45:23 +08:00   ❤️ 1
    https://imgur.com/a/vYwLyHl
    看了一下 Python 字节码,可以看到 aa 和 bb 都是编译成了全局变量了,cc 编译出来是局部变量;
    个人猜测:Python 看到没有出现过的变量名会先去全局找,但是看到 += 符号的时候回默认前面的变量是已经出现过的本地变量
    hsfzxjy
        2
    hsfzxjy  
       2023-03-20 22:47:25 +08:00 via Android
    这种情况下,加一句 global a 或 nonlocal a
    wynemo
        3
    wynemo  
       2023-03-20 22:47:52 +08:00
    >>> a = 5
    >>> id(a)
    4349762296
    >>> a += 6
    >>> id(a)
    4349762488

    因为生成新的对象了吧

    The global statement is a declaration which holds for the entire current code block. It means that the listed identifiers are to be interpreted as globals. It would be impossible to assign to a global variable without global, although free variables may refer to globals without being declared global.
    llsquaer
        4
    llsquaer  
       2023-03-20 23:03:28 +08:00
    a 是列表 容器可变类型 , 内存地址指向没有变.所以可以在函数内部修改..如果你把 a 改为 字符串..就改不了.

    基础问题. 你需要先了解 可变类型 和 不可变类型的区别.

    最后一个函数是 += 是累加赋值的意思. 列表确实是可以用+号扩展的.

    写全就是 a= 1 + a

    这个问题是 函数局部变量 a 还没有赋值, 函数内部是优先内部变量处理. a= 这个时候可以理解为暂存的变量,没有值,还没划分内存地址. =号后面才是真正的值.. 后面的 +a 加的是局部变量 a , 所以报错.. 因为你 + 的是还没值的自己..
    iOCZ
        5
    iOCZ  
       2023-03-20 23:14:48 +08:00
    引用 a 是全局的,但是赋值 a 的话,得加 global
    DOLLOR
        6
    DOLLOR  
       2023-03-20 23:18:33 +08:00
    这就是个陷阱。
    +=跟=一样,都会声明新的本地变量,所以第三个函数里的 a 其实是局部变量,而非外部的 a 。

    再一个更简单的例子:
    a = 1

    def f1():
    𰻝# 报错,此处的 a 不是外部的 a
    𰻝a += 1

    f1()

    回避方式:
    a = 1
    def f1():
    𰻝global a
    𰻝a += 1

    f1()
    print(a)
    mylifcc
        7
    mylifcc  
       2023-03-21 00:21:42 +08:00   ❤️ 1
    list 的加法 要用 a[:] += [3],如果使用 a += [3] 这种语法,则会创建一个新的列表对象,并将其赋值给 a 变量,而不是修改原始列表。
    zzl22100048
        9
    zzl22100048  
       2023-03-21 08:25:33 +08:00   ❤️ 1
    @mylifcc 不对吧,list += 会调用 __iadd__ 后做一个赋值,内部实际执行的是 extend 方法 并返回 self ,并没有创建新的列表对象。

    他这里用+= 对变量赋值了,导致函数内部会将 a 解析为局部变量
    aijam
        10
    aijam  
       2023-03-21 12:48:10 +08:00   ❤️ 1
    lovelylain
        11
    lovelylain  
       2023-03-21 12:55:05 +08:00 via Android   ❤️ 1
    a += x 相当于 a = a.__iadd__(x),对变量 a 重新赋值了,所以在没有 global 或 nonlocal 显式声明时被当做 local 变量,不过感觉这个不是很合理呀,因为 python 未定义变量是没法+=的,肯定是有在前面有=或者 import 赋值才行,既然这样+=就不应该作为变量是否本地的依据。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   951 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 21:04 · PVG 05:04 · LAX 14:04 · JFK 17:04
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.