Python 中的一些坑和坑和坑和弱智设计
一个不怎么文雅的吐槽,因为给 Python 气坏了,Python 傻逼语言。
前段时间给胡俊峰当 Python 的助教(工资还没发),发现这个语言的若干坑。
命名空间
其实这个机制很好的,垃圾就垃圾在 Python 创建引用的机制。
一个等号就是创建引用。创建引用就是新变量。
比如下面这段代码:
x = 1 def func(): x = 2 print(x)
当然是输出 1。
你说不对啊,为什么变量的值没改呢?因为 Python 根本没有变量,只有对象和对于对象的引用。你在函数内创建了一个对于 2
的引用,引用名称叫 x
,离开了函数空间这个引用就被销毁了。你说你外面还有个 x
啊?Python: 我管你呢。
如果要 Python “发现”一个外部的引用,那么需要关键字 global
,至少也得是个 nonlocal
。
可变与不可变
对于不可变对象,比如整数、字符串、元组这些对象,+=
是怎么发挥作用的呢?
x += 1
将被翻译成 x = x + 1
。换句话说,重新创建一个引用,引用名称是 x
,新对象是 x + 1
。
你说 C++ 不这样啊?那关我 Python 什么事呢。
根本原因是不可变对象只有成员函数 __add__
,而没有自增运算 __iadd__
。只有对于可变对象,x += 1
和 x = x + 1
才是有区别的。
>>> a = 'aba' >>> id(a) 140367141023280 >>> a += 'a' >>> id(a) 140367141023336 >>> a = [1, 2] >>> id(a) 140367140999880 >>> a += [3] >>> id(a) 140367140999880 >>> a = a + [3] >>> id(a) 140367141001736
一些神奇问题
同学 A 提问:我 list 怎么没了?
>>> a = [1, 2, 3, 4] >>> b = [5, 6, 7, 8] >>> c = zip(a, b) >>> c <zip object at 0x7fa9c593dbc8> >>> sorted(c) [(1, 5), (2, 6), (3, 7), (4, 8)] >>> list(c) []
zip 对象是一个 iterator。只有 next()
,迭代完了就没了。
同学 B 提问:Python 是不是不许我 dp 啊?
>>> n = 3 >>> m = 5 >>> dp = [[0] * n] * m >>> dp [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]] >>> dp[0][1] = 1 >>> dp [[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]]
Python: 真抱歉,list 的乘法是浅复制。
dp = [[0] * n for _ in range(m)]
上面是正确写法。