查看原文
其他

WTF Python: 开启你的懵逼模式

2017-10-07 大邓 大邓带你玩python

What the f*ck Python?

Python很流行很易学,但有时,Python代码片段的结果可能让小白们直接懵逼,现在大邓跟你一起开启懵逼模式

wtf-1 开胃菜hash

some_dict = {}
some_dict[5.5] = "Ruby"
some_dict[5.0] = "JavaScript"
some_dict[5] = "Python"

print(some_dict[5.5])
print(some_dict[5.0])
print(some_dict[5])

分析:

Ruby Python Python

Python字典检查相等,并比较key的hash值,以确定两个键是否相同。

同值不变的对象总是在Python中相同的hash值。

print(5==5.0)
print(hash(5)==hash(5.0))
True
True

wtf-2 生成器的if与in运行时间不同

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

print(list(g))

分析:

[8]

在Python的生成器语法中,in语句是在声明时就计算执行的,而if语句则是在运行时(调用g时)计算执行的。

也就是说,一开始我们告诉Python,当我们运行g时,g生成器in语句是在声明时确定有array有1、8、15,但是if语句是基于执行时查看发现array只有2、8、22,经过计算只有8出现1次。所以返回[8]。

tips:大家自己揣摩把,我解释的也不是很给力。

wtf-3 迭代时修改字典

x = {0: None}

for i in x:    del x[i]    x[i+1] = None    
   print(i)
0 1 2 3 4

分析:

只运行了5次,就停止了。

Python不支持迭代时对字典进行编辑(其实迭代时候也不能更改字典的容量)。

wtf-4 迭代时删除列表元素

list_1 = [1, 2, 3, 4]
list_2 = [1, 2, 3, 4]
list_3 = [1, 2, 3, 4]
list_4 = [1, 2, 3, 4]

for idx, item in enumerate(list_1):    del item

for idx, item in enumerate(list_2):    list_2.remove(item)

for idx, item in enumerate(list_3[:]):    list_3.remove(item)

for idx, item in enumerate(list_4):    list_4.pop(idx)    

print(list_1)
print(list_2)
print(list_3)
print(list_4)

分析:

[1, 2, 3, 4]
[2, 4]
[]
[2, 4]

在迭代ing时对自己进行修改是万万不可取的!!正确的做法是,使用备份数据迭代时对原数据进行修改。如list3,使用的是list3[:]。

some_list = [1, 2, 3, 4]

print(id(some_list))
print(id(some_list[:]))
4369310792 4369313544

del remove pop的区别

del varname仅仅删除局部或全局命名空间的varname所绑定的数据,这也是为什么list_1没有收到影响。

remove remove函数移除的是第一个匹配(match)的元素。

pop pop函数移除指定索引index值的元素,并且返回该元素。

为什么输出的是[2,4]?

第一次迭代 list2或者list4 为[1,2,3,4],index=0的元素为1。移除1

第二次迭代 list2或者list4 为[2,3,4],index=1的元素为3。移除3

第三次迭代 list2或者list4 为[3,4],没有index=2的元素,不再移除元素

所以,最后list2或者list4输出的是[2,4]

wtf-5 字符串后的反斜杠

print("\\ some string \\")
print(r"\ some string")

运行正常

\ some string \ \ some string

但这里,却运行出问题

print(r"\ some string \")  File "<ipython-input-27-605fb8dcbdb5>", line 1    print(r"\ some string \")                             ^ SyntaxError: EOL while scanning string literal

分析:

在raw字符串(以r为前缀)中,反斜杠没有特殊含义。

但是反斜杠不能再字符串末尾。

wtf-6 创建句型字符串

这部分不是python的奇葩问题,而是仅仅是为了学习运行效率。

import timeit

def add_string_with_plus(iters):    s = ""    for i in range(iters):        s += "xyz"    #当s长度等于3倍的iters时,断言。程序停止。    assert len(s) == 3*iters

def add_string_with_format(iters):    fs = "{}"*iters    s = fs.format(*(["xyz"]*iters))    assert len(s) == 3*iters    
def add_string_with_join(iters):    l = []    for i in range(iters):        l.append("xyz")    s = "".join(l)    assert len(s) == 3*iters

%timeit add_string_with_plus(10000)
%timeit add_string_with_format(10000)
%timeit add_string_with_join(10000)

分析:

1000 loops, best of 3: 1.63 ms per loop
1000 loops, best of 3: 778 µs per loop
1000 loops, best of 3: 1.44 ms per loop

从上面的例子我们以后要注意,拼接大量字符串时,+ 是很低效率的。最高效的是format,其次是join。

wtf-7 +=与+效率PK

def addequal():    s1 = ''    for i in range(10000):        s1 += str(i) + str(i+1)    return s1

def addonly():    s1 = ''    for i in range(10000):        s1 = s1 + str(i) + str(i+1)    return s1  
 %timeit addequal()
%timeit addonly()

分析:

100 loops, best of 3: 8.48 ms per loop
10 loops, best of 3: 28.5 ms per loop

+= 比 + 快很多。+= 方法是在s1原地进行赋值覆盖操作,而+方法,相当于重新新建一个s1,并把值赋值给s1。所以+=更高效。

wtf-8 is 与 ==

a = 256
b = 256
print('256 id',id(256))
print('a id:',id(a))
print('b id:',id(b))
print('a is b:',a is b)
print('a == b:',a == b)
256 id 4297632096
a id: 4297632096
b id: 4297632096
a is b: True
a == b: True

再来看看257

c = 257
d = 257
print('257 id',id(257))
print('c id:',id(c))
print('d id:',id(d))
print('c is d:',c is d)
print('c == d:',c == d)
257 id 4370421936
c id: 4370422000
d id: 4370420880
c is d: False
c == d: True

分析:

is is判断的是左右两边变量指向的是不是同一个对象(我们这里可以用变量的id判断是不是同一个对象。)

== ==判断的是左右两边的变量值是否相等。

当我们一启动python时,[-5,256]范围内的数值会被立刻分配出去。在上面的代码我们可以看到256、a、b的id都是相同的。

wtf-9 is not ... 不是 is (not ...)

print('not none' is not None)
print('not none' is (not None))
True
False

分析:

如果is not两边指向的是同一个对象,则返回False,否则返回True


😜好内容要多分享!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存