# Python WTF

Python是一门清晰易学的语言，可是这不代表我们Python没有黑暗料理，下面我就挑选了几个能让你大呼"卧槽，怎么会这样"的程序，这些例子不光有趣，也能够加深我们对于Python细节的理解，看看你自己能不能解释吧。

本文取材于下面这个GitHub repository。[satwikkansal/wtfpython​github.com![图标](https://pic4.zhimg.com/v2-84027475e590a8f2ddba7da13d0e7923_ipico.jpg)](http://link.zhihu.com/?target=https%3A//github.com/satwikkansal/wtfpython)

以下代码如果不信请手动尝试，测试环境：Python 3.6

### **20跟21有什么区别**

```
In [1]: 'a' * 20 is 'aaaaaaaaaaaaaaaaaaaa'
Out[1]: True

In [2]: 'a' * 21 is 'aaaaaaaaaaaaaaaaaaaaa'
Out[2]: False
```

第一次看到这个例子的时候我的心里面充满了wtf，20跟21有什么区别为什么结果不一样？原因是，python在进行内部优化的时候会做常量替换的操作，也就是把 'a' \* 20这种语句替换成'aaaaaaaaaaaaaaaaaaaa'，这样运行的时候节省时间，而刚好，小于等于20的时候会做这个优化，而大于20就不做这个优化了。。。

### **让一个函数Return两次**

```
In [3]: def some_func():
   ...:     try:
   ...:         return 'from_try'
   ...:     finally:
   ...:         return 'from_finally'
   ...:     

In [4]: some_func()
Out[4]: 'from_finally'
```

一般的Python教程会告诉你，当函数执行到第一个return的时候会退出，剩下的语句不再执行。然而如果是这样的话上面的代码中我们的somefunc()应该返回的是'from\_try'，但结果却不是。这个现象的原因是finally后面的语句永远会执行，而函数的返回值由最后一个return语句决定，所以函数的返回值是finally语句中的返回值。

### **循环几次？**

你猜下面的代码会循环几次

```
for i in range(4):
    print(i)
    i = 10
```

有些同学可能会猜只会循环一次，然后正确的输出是

```
０
１
２
３
```

循环了４次，所以i=10这个语句完全没用了吗？是的，这跟Python的for循环的机制有关，每次在循环体之前，下一个需要的值先会产生好然后赋值给循环变量，这里的i。也就是说，虽然循环体中有一个i = 10，但下次循环前for又会做一个i=2或者i=3的操作，把i=10覆盖了。

### **一石三鸟**

```
row = [''] * 3
board = [row] * 3
print(board)
==> [['', '', ''], ['', '', ''], ['', '', '']]
```

现在我们赋个值给第一个元素，再看看结果

```
board[0][0] = 'X'
print(board)
==> [['X', '', ''], ['X', '', ''], ['X', '', '']]
```

What?为什么有三个元素都变成了X，我们明明值赋了一个值啊？这是因为\[row] \* 3这个操作实际上没有复制row，而只是创建了三个object reference，也就是board\[0] board\[1] board\[2]这三个元素其实指向了同一个列表row，那么改变board\[0]\[0]其实就是改变row\[0]，也同时改变了board\[1]\[0] board\[2]\[0]。

### **又是数字，256和257有什么区别？**

```
In [45]: a = 256
In [46]: b = 256
In [47]: a is b
Out[47]: True

In [48]: a = 257
In [49]: b = 257
In [50]: a is b
Out[50]: False

In [58]: a, b = 257, 257
In [59]: a is b
Out[59]: True
```

嗼嗼嗼，这又是怎么回事？这又引出了Python另一个优化机制，在解释器开始的时候，会初始化-5到256这些数字，因为这些数字是常用的。所以a=256实际上是把a指向了已经创建好的256，b也同理。而257并没有预先创建好，每一行的代码在解释器里面又是单独优化的，所以写b=257的时候解释器不知道已经有了一个257，又新建了一个，因此他们俩指向不同的object。但当在一行里面同时给a b赋值为257的时候，解释器优化知道这点，就只创建了一个257，所以a is b又是True了。补充说明一下，这个现象只存在于repl交互执行当中，如果你把这些语句写在一个文件里面运行，那么编译器会一起优化，所有的结果都是True了。



{% embed url="https://github.com/satwikkansal/wtfpython" %}

{% embed url="https://zhuanlan.zhihu.com/p/40184557" %}
