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 2
a 相当于全局变量
x = a 的作用是创建一个局部变量 x ,这个 x 是 bar 内部的 x 不是 foo 里的 x ,你要用 foo 里的 x 要加上 nonlocal |
2
rglee 2021-12-16 15:09:13 +08:00 via Android 3
此 x 非彼 x ,用 id()看一下?
|
3
ipwx 2021-12-16 15:10:58 +08:00 1
如果你在 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 1
赋值即重新定义, 所以 bar 里面的 x 是在 bar 作用域中的 x,不会影响到 foo 中的 x
|
5
foobear 2021-12-16 16:05:16 +08:00 5
https://pythontutor.com/visualize.html 把你的代码复制到上面跑一遍就明白了
|
6
Skiro 2021-12-16 17:20:05 +08:00 via Android 1
问题 1: 为什么在 bar 函数内能访问 a 呢
回答:因为 a 是全局变量。 问题 2: 能访问按道理能赋值啊,x 咋还是 0 回答:因为实际上赋值成功的是 bar()里的 x ,这里 x ==100 ,而你输出的是 foo()里的 x 。 |
7
jaredyam 2021-12-16 17:40:56 +08:00 1
前几层已经说得很明白的,问题 2 也不是 Python 的问题。
|
8
DOLLOR 2021-12-16 18:19:46 +08:00 via Android 1
python 里,等号不仅有赋值的作用,还有声明变量的作用,相当于 JS 的 var 。
比如 x=a ,其实干了两件事情,一是在当前作用域声明了一个叫 x 的变量,二是赋值为 a 。 只要声明了变量,当前作用域内无论哪个位置,都再也不能访问外部的同名变量。 |
9
ch2 2021-12-16 18:30:01 +08:00 1
bar 可以访问 foo 里的 x,但是 bar 里直接修改 x 不行
|
10
ila 2021-12-16 18:35:35 +08:00 via Android 1
用类或全局变量
|
11
vance123 2021-12-16 19:00:15 +08:00 via Android 2
是有意设计成这样的
函数引用自己作用域内不存在的变量时,可以报错,也可以顺着词法环境往上搜索,python 选择了后者。 函数在内部赋值时,可以选择对已有变量赋值,或者重新定义一个变量,python 选择了后者。 原则是选择最合乎逻辑的那一个方案 |
12
flyhelan 2021-12-16 19:02:57 +08:00 1
不如 在 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 1
进入 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 1
关键词:作用域,局部变量与全局变量
拓展:形参 实参 |
16
xiaoxinshiwo 2021-12-16 19:26:29 +08:00 1
@foobear 棒
|
17
powerman 2021-12-16 19:32:49 +08:00 1
懒得很,我从来都是把所有语言当成 类 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 是全局作用域
![屏幕截图 2021-12-17 122430.png]( https://nf-1252257903.cos.ap-chengdu.myqcloud.com/2021/12/17/1a7583baaf637.png) |
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> |