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 为什么也继承了这个问题?
     1 
                    
                    1daydayde      2020-08-04 09:34:14 +08:00 
                    
                    这就是 Python.jpg 
                 | 
            
     2 
                    
                    domosekai      2020-08-04 09:34:23 +08:00 via Android 
                    
                    解释语言的锅? 
                 | 
            
     3 
                    
                    zachlhb      2020-08-04 09:36:52 +08:00 via Android 
                    
                    变量名不要起成一样的 
                 | 
            
     4 
                    
                    sixway      2020-08-04 09:37:16 +08:00 
                    
                    
                 | 
            
     5 
                    
                    optional      2020-08-04 09:39:48 +08:00 via iPhone 
                    
                    函数作用域是很多语言的特性啊,比如 c89 es5 
                 | 
            
     6 
                    
                    GlobalNPC      2020-08-04 09:40:11 +08:00 
                    
                    我记得之前查过说 因为 for 循环不是函数体,所以这里的变量与 for 是同级的,所以注意命名吧 
                 | 
            
     7 
                    
                    youthfire      2020-08-04 09:40:23 +08:00 via iPhone 
                    
                    没有学过其他语言,所以我的作法是一段代码封装一个函数就隔离了 
                 | 
            
     8 
                    
                    AV1      2020-08-04 09:42:16 +08:00    js 的 var 声明也是这样的,是函数级作用域,会提升到函数开始处,不过后来有了 let 和 const 这两,用来声明块级作用域,不再有这种问题了。 
                 | 
            
     9 
                    
                    magiclx      2020-08-04 09:56:55 +08:00 
                    
                    其实 for 循环结束后,如果你想知道 i 最后的值,能访问到 i 没什么不好的。 
                其实是需要养成一个习惯,如果后面新使用 i 时,必须赋初始值。  | 
            
     10 
                    
                    xiaolinjia      2020-08-04 10:01:00 +08:00 
                    
                    你这个问题确实是这样的,所以我一般用列表推导,就没这个问题( Py3 限定) 
                [i for i in range(10)] print(i) NameError: name 'i' is not defined  | 
            
     11 
                    
                    laike9m      2020-08-04 10:08:03 +08:00 via Android 
                    
                    其实就是语言没设计好。。 
                 | 
            
     12 
                    
                    Vegetable      2020-08-04 10:12:39 +08:00    设计就是设计,这个设计并没有带来什么真正的问题,不像 js 的 var 一样反认知。 
                 | 
            
     13 
                    
                    qdzzyb      2020-08-04 10:16:45 +08:00 
                    
                    这个还好吧 也没规定 for 一定要开启一个作用域吧 
                 | 
            
     14 
                    
                    msg7086      2020-08-04 10:17:10 +08:00 
                    
                    因为他是 Python,他不是其它语言。 
                而且 C++之前的 for 循环声明的变量也是会算在外作用域的,后来规范里明确要求放进内部作用域,才改成了现在这样。  | 
            
     15 
                    
                    whoami9894      2020-08-04 10:22:59 +08:00 
                    
                    Python 只有 def, class, lambda, [i for i ...]会引入新作用域 
                 | 
            
     17 
                    
                    yzqtdu      2020-08-04 10:26:39 +08:00    这个问题我找到[一篇博客]( https://eli.thegreenplace.net/2015/the-scope-of-index-variables-in-pythons-for-loops/) 
                这应该是语言的设计问题,前阵子看的 plp 刚好讲了 for 循环的语义复杂性,不光有 index 的访问问题,还有循环体内修改 index 和结束标记的问题  | 
            
     18 
                    
                    est      2020-08-04 10:31:33 +08:00    循环都是单字母变量。如果你污染外边的「作用域」了说明你单字母变量是不是太多了? 23333333333 
                 | 
            
     19 
                    
                    vagrantear      2020-08-04 11:47:35 +08:00    为什么别人设计的语言一定要遵循你的想法呢,你还能指望每个语言都一模一样? 
                 | 
            
     20 
                    
                    Ehend      2020-08-04 11:49:57 +08:00 via Android 
                    
                    这就是我放弃 Python 的原因,但也方便不少,不喜欢就换 Java 或者 c++吧。ps:已经换 c++。 
                 | 
            
     21 
                    
                    wuwukai007      2020-08-04 11:50:00 +08:00 via Android 
                    
                    for 后面可以写 else,拿到最后一个值做处理 
                 | 
            
     22 
                    
                    nnqijiu      2020-08-04 11:52:46 +08:00 
                    
                    为什么这么设计,你就得去问 python 开发者了 
                 | 
            
     23 
                    
                    Nich0la5      2020-08-04 12:08:31 +08:00 via Android 
                    
                    这叫语言特性  feature 
                 | 
            
     24 
                    
                    lolizeppelin      2020-08-04 14:11:08 +08:00 
                    
                    @est  
                你这样黑人太皮了呀  | 
            
     25 
                    
                    oooooooooooo      2020-08-04 14:33:00 +08:00 
                    
                    PHP 是不是 C 家族的? js 、php 、ruby .... 这些解释型语言,哪个有块级作用域???怎么就变成 Python 的 feature 了? 
                 | 
            
     26 
                    
                    threebr      2020-08-04 14:41:35 +08:00 via Android 
                    
                    我还挺喜欢这个特性的,实现一些科学计算中的算法很方便 
                 | 
            
     27 
                    
                    SergeGao      2020-08-04 14:51:20 +08:00 
                    
                    @oooooooooooo 杠一下,es6 的 let,const 引入了块级作用域.. 
                 | 
            
     28 
                    
                    misaka19000      2020-08-04 14:56:42 +08:00 
                    
                    我喜欢这个特性 
                 | 
            
     29 
                    
                    lovecy      2020-08-04 15:16:07 +08:00 
                    
                    每个语言都有自己的变量作用域,你习惯性认为 for 和 while 里面是独立的块级作用域,就想让其他语言都这么做。。。 
                @oooooooooooo 对啊,C 家族挺多无块级作用域的  | 
            
     30 
                    
                    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); } 具体不用说什么了吧  | 
            
     31 
                    
                    krixaar      2020-08-04 15:43:29 +08:00    换个场景,现在有个 for 循环,需要知道 break 之前运行了多少次,该怎么写? 
                外面先 int counter = 0;,然后里面 counter++,还是直接看运行完之后 i 是多少更方便? i 想污染外面变量的前提是外面有变量叫 i 能污染,那能不能规避不就是写代码的你自己的问题了吗?  | 
            
     32 
                    
                    yemoluo      2020-08-04 15:59:41 +08:00 
                    
                    
                 | 
            
     33 
                    
                    midtin      2020-08-04 17:29:19 +08:00    应该是因为 C 语言定义了 for 或 while 里面是一个代码块,所以有独立的作用域,而 Python 并没有把 for 和 while 视为一个代码块,没有给予独立的作用域。 
                实际上这个是语言特性,并不是什么设计缺陷, 譬如当业务需要在循环外检查中断原因时有很棒的作用。 而变量污染更多应该是靠人来规避的,别都甩锅给语言  | 
            
     34 
                    
                    crella      2020-08-04 18:45:10 +08:00 via Android 
                    
                    我记得 ruby 的循环是相对独立的,循环中会改变上文的变量,但是下文无法识别 do;end 循环中的变量;下文可以识别 for in;end 循环中的变量。 
                真的很讨厌:‘’解释型语言的什么问题‘’一竿子打翻一船人的行为。 另外 ruby 的 for while until 循环可以不用打 do 字符。  | 
            
     35 
                    
                    crella      2020-08-04 18:48:27 +08:00 via Android 
                    
                    ruby 里好像很多语法都有相似而备用的用法,比如 define_method 用来穿透作用域,lambda {}’里支持显式 return 来支持复杂循环退出,等等。不过无法跨线程 catch 和 throw 让我不爽。 
                 | 
            
     36 
                    
                    northisland      2020-08-04 20:55:10 +08:00    尝试解释一下, 
                c++,很多情况下,变量名就是数据。 python 的变量名就是个名字,需要和数据绑定。 循环变量 i 的数据没有回收, 变量名没有回收, 绑定关系也没有回收, 当然可以访问 i 了。 看开点,语法不是重点~  | 
            
     37 
                    
                    northisland      2020-08-04 20:57:30 +08:00 
                    
                    python 这语言浪的很 
                 | 
            
     38 
                    
                    fasionchan      2020-08-05 08:44:19 +08:00 
                    
                    @sixway 闭包不是问题的根源,相反它是受害者。循环没有独立作用域,会导致很多非预期的行为,在循环中定义的闭包函数就是典型的一例。Python 中变量的行为跟 JavaScript 中 var 定义的变量一样,都是函数作用域。但 JavaScript 后来引入 let 和 const 关键字,作用域缩小到代码块,这样闭包就不会有非预期行为了。 
                 |