Python:What the f*ck Python(上) (2)

说明:
这一条仔细看一下很好理解,for 循环每次迭代都会给分配目标赋值,some_dict[i] = value 就相当于给字典添加键值对了。
有趣的是下面这个例子,你可曾觉得这个循环只会运行一次?

for i in range(4): print(i) i = 10 6. Evaluation time discrepancy

>>> array = [1, 8, 15] >>> g = (x for x in array if array.count(x) > 0) >>> array = [2, 8, 22] >>> list(g) [8]

>>> array_1 = [1, 2, 3, 4] >>> g1 = (x for x in array_1) >>> array_1 = [1, 2, 3, 4, 5] >>> array_2 = [1, 2, 3, 4] >>> g2 = (x for x in array_2) >>> array_2[:] = [1, 2, 3, 4, 5] >>> list(g1) [1, 2, 3, 4] >>> list(g2) [1, 2, 3, 4, 5]

说明:
在生成器表达式中 in 子句在声明时执行,而条件子句则是在运行时执行。
①中,在运行前 array 已经被重新赋值为 [2, 8, 22],因此对于之前的 1, 8, 15,只有 count(8) 的结果是大于 0 ,所以生成器只会生成 8。
②中,g1 和 g2 的输出差异则是由于变量 array_1 和 array_2 被重新赋值的方式导致的。

在第一种情况下,array_1 被绑定到新对象 [1, 2, 3, 4, 5],因为 in 子句是在声明时被执行的,所以它仍然引用旧对象 [1, 2, 3, 4](并没有被销毁)。

在第二种情况下,对 array_2 的切片赋值将相同的旧对象 [1, 2, 3, 4] 原地更新为 [1, 2, 3, 4, 5]。因此 g2 和 array_2 仍然引用同一个对象[1, 2, 3, 4, 5]。

7. is is not what it is! >>> a = 256 >>> b = 256 >>> a is b True >>> a = 257 >>> b = 257 >>> a is b False >>> a = 257; b = 257 >>> a is b True

说明:
is 和 == 的区别

is 运算符检查两个运算对象是否引用自同一对象

== 运算符比较两个运算对象的值是否相等

因此 is 代表引用相同,== 代表值相等。下面的例子可以很好的说明这点:

>>> [] == [] True >>> [] is [] # 这两个空列表位于不同的内存地址 False

256 是一个已经存在的对象,而 257 不是
当启动 Python 的时候,-5 到 256 的数值就已经被分配好了。这些数字因为经常使用所以适合被提前准备好。

当前的实现为 -5 到 256 之间的所有整数保留一个整数对象数组,当你创建了一个该范围内的整数时,你只需要返回现有对象的引用。所以改变 1 的值是有可能的。

但是,当 a 和 b 在同一行中使用相同的值初始化时,会指向同一个对象。

>>> id(256) 10922528 >>> a = 256 >>> b = 256 >>> id(a) 10922528 >>> id(b) 10922528 >>> id(257) 140084850247312 >>> x = 257 >>> y = 257 >>> id(x) 140084850247440 >>> id(y) 140084850247344 >>> a, b = 257, 257 >>> id(a) 140640774013296 >>> id(b) 140640774013296

这是一种特别为交互式环境做的编译器优化,当你在实时解释器中输入两行的时候,他们会单独编译,因此也会单独进行优化, 如果你在 .py 文件中尝试这个例子,则不会看到相同的行为,因为文件是一次性编译的。

8. A tic-tac-toe where X wins in the first attempt! >>> row = [''] * 3 >>> board = [row] * 3 >>> board [['', '', ''], ['', '', ''], ['', '', '']] >>> board[0] ['', '', ''] >>> board[0][0] '' >>> board[0][0] = "X" >>> board [['X', '', ''], ['X', '', ''], ['X', '', '']]

说明:
我们来输出 id 看下:

>>> id(row[0]) 7536232 >>> id(row[1]) 5143216 >>> id(row[2]) 5143216 >>> id(board[0]) 7416840 >>> id(board[1]) 7416840 >>> id(board[2]) 7416840

row 是一个 list,其中三个元素都指向地址 5143216,当对 board[0][0] 进行赋值以后,row 的第一个元素指向 7536232。而 board 中的三个元素都指向 row,row 的地址并没有改变。

我们可以通过不使用变量 row 生成 board 来避免这种情况。

>>> board = [[''] * 3 for _ in range(3)] >>> board[0][0] = "X" >>> board [['X', '', ''], ['', '', ''], ['', '', '']]

这里用了推导式,每次迭代都会生成一个新的 _ ,所以 board 中三个元素指向的是不同的变量。

9. The sticky output function funcs = [] results = [] for x in range(7): def some_func(): return x funcs.append(some_func) results.append(some_func()) funcs_results = [func() for func in funcs]

Output:

>>> results [0, 1, 2, 3, 4, 5, 6] >>> funcs_results [6, 6, 6, 6, 6, 6, 6]

说明:
当在循环内部定义一个函数时,如果该函数在其主体中使用了循环变量,则闭包函数将与循环变量绑定,而不是它的值。因此,所有的函数都是使用最后分配给变量的值来进行计算的。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpdgwf.html