APP下载
报价宝  ›  科技  › 

Python的51个秘密被曝光 |GitHub超2万星

报价宝 来源:baojiabao.com 发布时间:2019-11-13 02:49:00 11月12日更新
报价宝综合消息Python的51个秘密被曝光 |GitHub超2万星

Python,是一个设计优美的解释型高阶语言,它提供了很多能让程序员感到舒适的功能特性。

但有的时候,Python一些特性导致的输出结果,对于初学者就很难理解了。

一个解析51项堪称是“秘密”的Python特性专案,在GitHub上彻底火了。

英文原版已经拿到了近15000星,中文翻译版也获得了7500+星。

专案中的部分内容,也许你听说过,但依然可能会透露一些你所不知道的Python有趣特性。

我觉得这是学习程式语言内部原理的好机会,而且我相信你也会从中获得乐趣!

如果你是一位经验比较丰富的Python程序员,你可以试试能否一次就找到正确答案。

也许你对其中的一些例子比较熟悉,那这些案例能唤起你当年踩坑时的甜蜜回忆。

示例的结构

所有示例的结构都如下所示:

> 一个精选的标题

Output (Python version):

(可选): 对意外输出结果的简短描述。

说明:

简要说明发生了什么以及为什么会发生。

Output:

注意:所有的示例都在Python3.5.2版本的互动直译器上测试过,如果不特别说明应该适用于所有Python版本。

用法

我个人建议,最好依次阅读下面的示例,并仔细阅读设定例子最开始的程式码。

阅读输出结果

示例

1.

2.

3.

说明:

这些行为是由于 Cpython 在编译优化时,某些情况下会尝试使用已经存在的不可变物件,而不是每次都建立一个新物件。(这种行为被称作字串的驻留[string interning])

发生驻留之后,许多变数可能指向内存中的相同字串物件。(从而节省内存)

在上面的程式码中,字串是隐式驻留的。何时发生隐式驻留则取决于具体的实现。这里有一些方法可以用来猜测字串是否会被驻留:

当在同一行将 a 和 b 的值设定为 "wtf!" 的时候, Python 直译器会建立一个新物件, 然后同时引用第二个变数。

如果你在不同的行上进行赋值操作, 它就不会“知道”已经有一个 wtf! 物件 (因为 "wtf!" 不是按照上面提到的方式被隐式驻留的)。

它是一种编译器优化,特别适用于互动式环境。

常量折叠(constant folding) 是 Python 中的一种窥孔优化(peephole optimization) 技术。

这意味着在编译时表示式 'a'*20 会被替换为 'aaaaaaaaaaaaaaaaaaaa' 以减少执行时的时钟周期。

只有长度小于 20 的字串才会发生常量折叠。(为啥? 想象一下由于表示式'a'*10**10 而生成的 .pyc 档案的大小)相关的源代码:

https://github.com/python/cpython/blob/3.6/Python/peephole.c#L288

1.

Output:

"Python" 消除了 "JavaScript" 的存在?

说明:

Python 字典通过检查键值是否相等和比较杂凑值来确定两个键是否相同。

具有相同值的不可变物件在Python中始终具有相同的杂凑值。

注意: 具有不同值的物件也可能具有相同的杂凑值(杂凑冲突)。

当执行 some_dict[5] = "Python" 语句时, 因为Python将 5 和 5.0 识别为 some_dict 的同一个键, 所以已有值 "JavaScript" 就被 "Python" 覆盖了。

Output:

说明:

当在 "try...finally" 语句的 try 中执行 return, break 或 continue 后, finally 子句依然会执行。

函式的返回值由最后执行的 return 语句决定。

由于 finally 子句一定会执行, 所以 finally 子句中的 return 将始终是最后执行的语句。

Output:

说明:

当呼叫 id 函式时, Python 建立了一个 WTF 类的物件并传给 id 函式。

然后 id 函式获取其id值 (也就是内存地址), 然后丢弃该物件. 该物件就被销毁了。

当我们连续两次进行这个操作时, Python会将相同的内存地址分配给第二个物件。 因为 (在CPython中) id 函式使用物件的内存地址作为物件的id值, 所以两个物件的id值是相同的。

综上, 物件的id值仅仅在物件的生命周期内唯一。在物件被销毁之后, 或被建立之前, 其他物件可以具有相同的id值。

那为什么 is 操作的结果为 False 呢? 让我们看看这段程式码:

Output:

正如你所看到的, 物件销毁的顺序是造成所有不同之处的原因。

Output:

其中 exprlist 指分配目标. 这意味着对可迭代物件中的每一项都会执行类似 {exprlist} = {next_value} 的操作。

一个有趣的例子说明了这一点:

由于循环在Python中工作方式, 赋值语句 i = 10 并不会影响迭代循环, 在每次迭代开始之前, 迭代器(这里指 range(4)) 生成的下一个元素就被解包并赋值给目标列表的变数(这里指 i)了。

在每次迭代中, enumerate(some_string) 函式就生成一个新值 i (计数器增加) 并从 some_string 中获取一个字元。

然后将字典 some_dict 键 i (刚刚分配的) 的值设为该字元。本例中循环的展开可以简化为:

1.

Output:

2.

Output:

说明:

在生成器表示式中, 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])。

本文内容来自中文版专案,专案全文2万多字,以及海量程式码。

因为篇幅原因,小七就先只为大家展示这6个案例,后续会逐步更新。

原价800元的Python入门课程

现在限时免费!没有任何要求,直接领取就可以!

任何疑问,教师团队随时解答。

虽然是免费课,但教师团队可没有缩水,依旧是BAT高阶专家配合顶级高校硕士进行教学。

回复“Python”,开始学习。

每天更新干货,帮你踏入AI领域成为技术leader。

应届生学员转行拿到52万年薪,大量学员转行后拿到30-40万年薪!

讲师均由各大公司技术leader和国内外顶级高校博士组成!

马上开始学习,和“前辈们”一样进入心仪公司,夺取高薪,成为人生赢家。

文章标签: 报价宝 降噪耳机价格 耳机价格 红米手机价格 华为手机价格 小米手机价格 电视机价格 笔记本电脑价格 笔记本价格 汽车价格 报价宝 汽车价格 笔记本价格 华为手机价格 耳机价格