def foo(): c = "hello" x = 0 def bar(): b = True print(a) print(b) print(c) x = a bar() print(x) if __name__ == "__main__": a = 100 foo()
结果就是: 100 True hello 0
问题 1: 为什么在 bar 函数内能访问 a 呢 问题 2: 能访问按道理能赋值啊,x 咋还是 0
![]() | 1 jxxz 2021-12-16 15:06:42 +08:00 ![]() a 相当于全局变量 x = a 的作用是创建一个局部变量 x ,这个 x 是 bar 内部的 x 不是 foo 里的 x ,你要用 foo 里的 x 要加上 nonlocal |
2 rglee 2021-12-16 15:09:13 +08:00 via Android ![]() 此 x 非彼 x ,用 id()看一下? |
![]() | 3 ipwx 2021-12-16 15:10:58 +08:00 ![]() 如果你在 foo 里面 a = 200 ,然后在 foo() 之后 print(a),你会发现 foo 里面的 a 和外面的 a 就不是一个 a 了。 我觉得这是 Python 让人不满意的地方。因为没有声明,赋值即声明,所以会搞不清楚作用域。 事实上如果你运行如下代码: def main(): ....print(a) ....a = 1 a = 2 main() 你会得到一个异常: UnboundLocalError: local variable 'a' referenced before assignment 原因是 a = 1 这句话在 main 函数里面定义了一个变量 a ,因此你在 print(a) 这一行就引用不到全局的 a 了。 |
![]() | 4 ddmasato 2021-12-16 15:52:37 +08:00 ![]() 赋值即重新定义, 所以 bar 里面的 x 是在 bar 作用域中的 x,不会影响到 foo 中的 x |
![]() | 5 foobear 2021-12-16 16:05:16 +08:00 ![]() https://pythontutor.com/visualize.html 把你的代码复制到上面跑一遍就明白了 |
6 Skiro 2021-12-16 17:20:05 +08:00 via Android ![]() 问题 1: 为什么在 bar 函数内能访问 a 呢 回答:因为 a 是全局变量。 问题 2: 能访问按道理能赋值啊,x 咋还是 0 回答:因为实际上赋值成功的是 bar()里的 x ,这里 x ==100 ,而你输出的是 foo()里的 x 。 |
![]() | 7 jaredyam 2021-12-16 17:40:56 +08:00 ![]() 前几层已经说得很明白的,问题 2 也不是 Python 的问题。 |
![]() | 8 AV1 2021-12-16 18:19:46 +08:00 via Android ![]() python 里,等号不仅有赋值的作用,还有声明变量的作用,相当于 JS 的 var 。 比如 x=a ,其实干了两件事情,一是在当前作用域声明了一个叫 x 的变量,二是赋值为 a 。 只要声明了变量,当前作用域内无论哪个位置,都再也不能访问外部的同名变量。 |
![]() | 9 ch2 2021-12-16 18:30:01 +08:00 ![]() bar 可以访问 foo 里的 x,但是 bar 里直接修改 x 不行 |
10 ila 2021-12-16 18:35:35 +08:00 via Android ![]() 用类或全局变量 |
![]() | 11 vance123 2021-12-16 19:00:15 +08:00 via Android ![]() 是有意设计成这样的 函数引用自己作用域内不存在的变量时,可以报错,也可以顺着词法环境往上搜索,python 选择了后者。 函数在内部赋值时,可以选择对已有变量赋值,或者重新定义一个变量,python 选择了后者。 原则是选择最合乎逻辑的那一个方案 |
![]() | 12 flyhelan 2021-12-16 19:02:57 +08:00 ![]() 不如 在 x = a 后 再加一行 print(x) 你体会一下。bar 里的 x 和 foo 里的 x 不是同一个 x 。 def foo(): c = "hello" x = 0 def bar(): b = True print(a) print(b) print(c) x = a print(x) bar() print(x) if __name__ == "__main__": a = 100 foo() |
![]() | 14 kidblg 2021-12-16 19:15:47 +08:00 ![]() 进入 foo 之前,产生的作用域 1 内:a=100 进入 foo 后,产生的作用域 2 内:c=hello, x=0 ,而且因为函数内可以访问函数外的变量,所以可以访问 a=100 进入 bar 时,产生的作用域 3 内:b=true, x=a ,但 bar 退出时,就销毁这个新的作用域 所以 x 是 100 |
![]() | 15 rationa1cuzz 2021-12-16 19:26:09 +08:00 ![]() 关键词:作用域,局部变量与全局变量 拓展:形参 实参 |
![]() | 16 xiaoxinshiwo 2021-12-16 19:26:29 +08:00 ![]() @foobear 棒 |
![]() | 17 powerman 2021-12-16 19:32:49 +08:00 ![]() 懒得很,我从来都是把所有语言当成 类 C 语言的风格来写,根本不关心变量作用域 |
![]() | 18 inframe 2021-12-16 22:09:57 +08:00 python 变量搜索顺序是 LEGB, https://www.cnblogs.com/xuexianqi/p/13658528.html |
![]() | 19 zhaohehedola 2021-12-16 22:56:56 +08:00 via iPhone 外层变量 可读不可写 |
20 echoechoin 2021-12-17 10:04:11 +08:00 闭包 |
![]() | 21 NanFengXiangWan 2021-12-17 12:24:48 +08:00 因为变量 a 是全局作用域  |
![]() | 22 flyhelan 2022-03-03 17:21:50 +08:00 <section id="nice" data-tool="mdnice 编辑器" data-website="https://www.mdnice.com" style="font-size: 16px; color: black; padding: 0 10px; line-height: 1.6; word-spacing: 0px; letter-spacing: 0px; word-break: break-word; word-wrap: break-word; text-align: left; font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;"><pre class="custom" data-tool="mdnice 编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block; background: url( https://files.mdnice.com/user/3441/876cad08-0422-409d-bb5a-08afec5da8ee.svg); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #282c34; border-radius: 5px;"><span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">def</span> <span class="hljs-title" style="color: #61aeee; line-height: 26px;">foo</span><span class="hljs-params" style="line-height: 26px;">()</span>:</span><br> c = <span class="hljs-string" style="color: #98c379; line-height: 26px;">"hello"</span><br> x = <span class="hljs-number" style="color: #d19a66; line-height: 26px;">0</span><br> <span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">def</span> <span class="hljs-title" style="color: #61aeee; line-height: 26px;">bar</span><span class="hljs-params" style="line-height: 26px;">()</span>:</span><br> b = <span class="hljs-literal" style="color: #56b6c2; line-height: 26px;">True</span><br> print(a)<br> print(b)<br> print(c)<br> x = a<br> print(x) <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;"># 新增这条</span><br> bar()<br> print(x)<br><br><br><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> __name__ == <span class="hljs-string" style="color: #98c379; line-height: 26px;">"__main__"</span>:<br> a = <span class="hljs-number" style="color: #d19a66; line-height: 26px;">100</span><br> foo()<br></code></pre> </section> |