Python 的 for 和 while 循环为什么没有引入新的作用域?

2020-08-04 09:25:56 +08:00
 CNife

C 家族的编程语言,基本都会为 for 和 while 循环引入新的作用域,以保证循环里定义的局部变量不会污染外部作用域。

for (int i = 0; i < 10; i++) {
    printf("%d\n", i);
}
// 无法再访问 i

但 Python 不是这样,for 和 while 循环内的局部变量会在循环后继续保留,依然可以被访问。也就是说,for 和 while 循环没有引入新的作用域。

for i in range(10):
    print(i)
print(i) # 可以访问,i=9

很明显,这样的做法会造成很多不必要的错误,比如循环内的变量遮盖了外部作用域的变量,循环结束后使用了被循环污染的变量等。

Python2 有这样的问题可以归结为历史原因,Python3 为什么也继承了这个问题?

5012 次点击
所在节点    Python
38 条回复
wuwukai007
2020-08-04 11:50:00 +08:00
for 后面可以写 else,拿到最后一个值做处理
nnqijiu
2020-08-04 11:52:46 +08:00
为什么这么设计,你就得去问 python 开发者了
Nich0la5
2020-08-04 12:08:31 +08:00
这叫语言特性 feature
lolizeppelin
2020-08-04 14:11:08 +08:00
@est
你这样黑人太皮了呀
oooooooooooo
2020-08-04 14:33:00 +08:00
PHP 是不是 C 家族的? js 、php 、ruby .... 这些解释型语言,哪个有块级作用域???怎么就变成 Python 的 feature 了?
threebr
2020-08-04 14:41:35 +08:00
我还挺喜欢这个特性的,实现一些科学计算中的算法很方便
SergeGao
2020-08-04 14:51:20 +08:00
@oooooooooooo 杠一下,es6 的 let,const 引入了块级作用域..
misaka19000
2020-08-04 14:56:42 +08:00
我喜欢这个特性
lovecy
2020-08-04 15:16:07 +08:00
每个语言都有自己的变量作用域,你习惯性认为 for 和 while 里面是独立的块级作用域,就想让其他语言都这么做。。。
@oooooooooooo 对啊,C 家族挺多无块级作用域的
0x4C
2020-08-04 15:22:44 +08:00
Python 的 for
for <variable> in <sequence>:
<statements>
else:
<statements>


C++的 for
for ( init; condition; increment )
{
statement(s);
}

具体不用说什么了吧
krixaar
2020-08-04 15:43:29 +08:00
换个场景,现在有个 for 循环,需要知道 break 之前运行了多少次,该怎么写?
外面先 int counter = 0;,然后里面 counter++,还是直接看运行完之后 i 是多少更方便?
i 想污染外面变量的前提是外面有变量叫 i 能污染,那能不能规避不就是写代码的你自己的问题了吗?
GTim
2020-08-04 15:59:41 +08:00
midtin
2020-08-04 17:29:19 +08:00
应该是因为 C 语言定义了 for 或 while 里面是一个代码块,所以有独立的作用域,而 Python 并没有把 for 和 while 视为一个代码块,没有给予独立的作用域。

实际上这个是语言特性,并不是什么设计缺陷, 譬如当业务需要在循环外检查中断原因时有很棒的作用。

而变量污染更多应该是靠人来规避的,别都甩锅给语言
crella
2020-08-04 18:45:10 +08:00
我记得 ruby 的循环是相对独立的,循环中会改变上文的变量,但是下文无法识别 do;end 循环中的变量;下文可以识别 for in;end 循环中的变量。

真的很讨厌:‘’解释型语言的什么问题‘’一竿子打翻一船人的行为。

另外 ruby 的 for while until 循环可以不用打 do 字符。
crella
2020-08-04 18:48:27 +08:00
ruby 里好像很多语法都有相似而备用的用法,比如 define_method 用来穿透作用域,lambda {}’里支持显式 return 来支持复杂循环退出,等等。不过无法跨线程 catch 和 throw 让我不爽。
northisland
2020-08-04 20:55:10 +08:00
尝试解释一下,

c++,很多情况下,变量名就是数据。

python 的变量名就是个名字,需要和数据绑定。
循环变量 i 的数据没有回收,
变量名没有回收,
绑定关系也没有回收,
当然可以访问 i 了。


看开点,语法不是重点~
northisland
2020-08-04 20:57:30 +08:00
python 这语言浪的很
fasionchan
2020-08-05 08:44:19 +08:00
@sixway 闭包不是问题的根源,相反它是受害者。循环没有独立作用域,会导致很多非预期的行为,在循环中定义的闭包函数就是典型的一例。Python 中变量的行为跟 JavaScript 中 var 定义的变量一样,都是函数作用域。但 JavaScript 后来引入 let 和 const 关键字,作用域缩小到代码块,这样闭包就不会有非预期行为了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/695413

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX