Python是一门设计精美的解释型高级语言,提供了很多让程序员用得舒心的功能特性。但是有时候,Python的一些特性导致的输出结果,对于初学者来说是比较难理解的。一个解析51个“秘密”Python特性的项目在GitHub上完全流行。英文原版获得近15000星,中文译本也获得7500+星。您可能听说过该项目中的一些内容,但它仍然可能揭示您不知道的Python的一些有趣特性。我认为这是学习编程语言内部原理的绝好机会,我相信您也会从中获得乐趣!如果您是一位经验丰富的Python程序员,您可以尝试一下,看看您是否能在第一时间找到正确的答案。也许你对其中的一些例子很熟悉,这些案例能勾起你踩坑时的美好回忆。本项目中文版全文约2万字,干货快溢出来了。你可以先看看目录。示例结构所有示例的结构如下:>特色标题#准备代码。#Unleashthemagic...输出(Python版本):>>>触发语句意外输出结果(可选):是对意外输出结果的简短描述。解释:对发生的事情和发生原因的简要描述。ExampleifnecessaryOutput:>>>triggerstatement#someexamplesthatmakethemagiceasytounderstand#somenormalinput注意:所有示例都是在Python3.5.2版本的交互式解释器上测试的,如果不是特殊说明应该适用于所有Python版本。用法我个人建议最好一个一个看完下面的例子,仔细阅读设置例子开头的代码。阅读输出以确保结果符合您的预期。确保你知道这个ExampleSubtleString1背后的基本原理。>>>a="some_string">>id(a)140420665652016>>>id("some"+"_"+"string")#注意id两者的价值观是一样的。1404206656520162。>>>a="wtf">>b="wtf">>>aisbTrue>>>a="wtf!">>>b="wtf!">>>aisbFalse>>>a,b="wtf!","wtf!">>>aisbTrue3.>>>'a'*20is'aaaaaaaaaaaaaaaaaaaaa'True>>>'a'*21is'aaaaaaaaaaaaaaaaaaaa'False描述:这些行为是由于Cpython将在编译和优化时,在某些情况下尽量使用现有的不可变对象,而不是每次都创建一个新对象。(这种行为称为字符串驻留[stringinterning])发生驻留后,许多变量可能指向内存中的同一个字符串对象。(从而节省内存)在上面的代码中,字符串是隐式驻留的。何时发生隐式驻留取决于实现。这里有一些猜测字符串是否会常驻的方法:所有长度为0和长度为1的字符串都是常驻的。字符串在编译时具体化。('wtf'将常驻,但''.join(['w','t','f']不会常驻)仅包含字母、数字或下划线的字符串将常驻。所以'wtf!'是notresidentbecauseitcontains!.CPython对这个规则的实现可以在这里找到。当a和b被设置为"wtf!"在同一行时,Python解释器创建一个新对象,然后引用第二个变量在同时。如果您在不同的线路上进行分配,它不会“知道”已经有一个wtf!对象(因为“wtf!”不是隐式驻留在上面提到的方式中)。它是一种编译器优化,在交互式环境中特别有用。常量折叠是Python中的一种窥孔优化技术。这意味着表达式'a'*20将在编译时被替换为'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'以减少运行时的时钟周期。常量折叠只发生在长度小于20的字符串上。(为什么?想象一下由于表达式'a'*10**10生成的.pyc文件的大小)相关源代码:https://github.com/python/cpython/blob/3.6/Python/窥视孔。c#L288是时候吃蛋糕了!1.some_dict={}some_dict[5.5]="Ruby"some_dict[5.0]="JavaScript"some_dict[5]="Python"输出:>>>some_dict[5.5]"Ruby">>>some_dict[5.0]"Python”>>>some_dict[5]“Python”“Python”消除了“JavaScript”的存在?说明:Python字典是通过检查key是否相等,比较hash值来判断两个key是否相同。具有相同值的不可变对象在Python中始终具有相同的哈希值。>>>5==5.0True>>>hash(5)==hash(5.0)True注意:不同值的对象也可能有相同的哈希值(哈希冲突)。当执行语句some_dict[5]="Python"时,现有值"JavaScript"被"Python"覆盖,因为Python将5和5.0识别为some_dict中的相同键。处处归来!defsome_func():try:return'from_try'finally:return'from_finally'输出:>>>some_func()'from_finally'说明:执行return后,在“try...finally”语句的try中break或continue,finally子句仍然执行。函数的返回值由最后执行的return语句决定。由于finally子句保证被执行,所以finally子句中的return将始终是最后执行的语句。本质上我们都是同一个类WTF:passOutput:>>>WTF()==WTF()#两个不同的对象不应该相等False>>>WTF()isWTF()#不一样False>>>hash(WTF())==hash(WTF())#哈希值也要不同True>>>id(WTF())==id(WTF())True说明:调用id函数时,Python创建WTF类的对象并传递给id函数。然后id函数获取它的id值(也就是内存地址),然后丢弃这个对象。对象被销毁。当我们连续两次这样做时,Python将相同的内存地址分配给第二个对象。因为(在CPython中)id函数使用对象的内存地址作为对象的id值,所以两个对象的id值相同。综上所述,一个对象的id值只在该对象的生命周期内是唯一的。在对象被销毁之后,或者在它被创建之前,其他对象可以有相同的id值。那么为什么is操作的结果是False呢?让我们看一下这段代码:classWTF(object):def__init__(self):print("I")def__del__(self):print("D")(WTF())==id(WTF())IDIDTrue如您所见,对象销毁的顺序是造成所有差异的原因。为什么?some_string="wtf"some_dict={}fori,some_dict[i]inenumerate(some_string):passOutput:>>>some_dict#创建了一个索引字典。{0:'w',1:',2:'f'}说明:for在Python语法中的定义是:for_stmt:'for'exprlist'in'testlist':'suite['else'':'suite]其中exprlist指的是赋值目标。这意味着对于可迭代对象中的每个项目都会做类似{exprlist}={next_value}的事情。一个有趣的例子可以说明这一点:foriinrange(4):print(i)i=10Output:0123你有没有想过这个循环只会运行一次?说明:由于Python中循环的工作方式,赋值语句i=10并且在不影响迭代循环的情况下,将迭代器生成的下一个元素(此处为range(4))解包并赋值给目标列表的变量(此处,i)在每次迭代开始之前。在每次迭代中,enumerate(some_string)函数生成一个新值i(计数器递增)并从some_string中获取一个字符。然后将字典some_dictkeyi(刚刚分配)的值设置为该字符。本例中循环的展开可以简化为:>>>i,some_dict[i]=(0,'w')>>>i,some_dict[i]=(1,'t')>>>i,some_dict[i]=(2,'f')>>>some_dict执行时序差1.array=[1,8,15]g=(xforxinarrayifarray.count(x)>0)array=[2,8,22]输出:>>>print(list(g))[8]2.array_1=[1,2,3,4]g1=(xforxinarray_1)array_1=[1,2,3,4,5]array_2=[1,2,3,4]g2=(xforxinarray_2)array_2[:]=[1,2,3,4,5]输出:>>>print(list(g1))[1,2,3,4]>>>print(list(g2))[1,2,3,4,5]解释:在生成器表达式中,in子句在声明时执行,而条件子句在运行时执行。所以在运行之前,数组已经重新赋值给了[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个案例,更多案例可以在项目中查看。项目作者:SatwikKansal英文版项目名称:wtfpython中文版作者:MuChen中文项目名称:wtfpython-cn由于平台规定,不能贴链接。你可以自己搜索。
