51个Python鲜为人知的秘密特性,老司机看完都惊叹不已
Python真的很奇妙,目前是最火的语言。语法简单,功能强大,我学Python已经好多年了,从2.6的时代一直到现在的3.8,算算也是老鸟了。今天看了一个网站,上面讲了很多Python鲜为人知的特性,看完我也是大开眼界,不得不说,Python真实博大精深!
1.Midnight time doesn't exist?/不存在的午夜
>>
('Time at noon is', datetime.time(12, 0))
midnight_time 并没有被输出.在Python 3.5之前, 如果 datetime.time 对象存储的UTC的午夜时间(译: 就是 00:00), 那么它的布尔值会被认为是 False. 当使用 if obj: 语句来检查 obj 是否为 null 或者某些“空”值的时候, 很容易出错.
2.Time for some hash brownies!/是时候来点蛋糕了
>>
>>> some_dict[5.5]
"Ruby"
>>> some_dict[5.0]
"Python"
>>> some_dict[5]
"Python"
运行完发现"Javascript" 消失了,原因是因为Python 字典通过检查键值是否相等和比较哈希值来确定两个键是否相同. 而Python中 5==5.0 ,所以字符串Javascript被Python取代了。
3.For what?/为什么?
通过enumerate这个内置函数来迭代处理,大家猜猜some_dict输出是啥?
没错输出的是:{0: 'w', 1: 't', 2: 'f'}。 咋看一下确实很奇怪啊,我们来慢动作看一下:
相当于是:
some_dict[0] = 'w'
some_dict[1] = 't'
some_dict[2] = 'f'
4.Strings can be tricky sometimes/微妙的字符串
为啥这两个字符串的id值是一样的
说明:
- 这些行为是由于 Cpython 在编译优化时, 某些情况下会尝试使用已经存在的不可变对象而不是每次都创建一个新对象. (这种行为被称作字符串的驻留[string interning])
- 发生驻留之后, 许多变量可能指向内存中的相同字符串对象. (从而节省内存)
- 在上面的代码中, 字符串是隐式驻留的. 何时发生隐式驻留则取决于具体的实现. 这里有一些方法可以用来猜测字符串是否会被驻留:
- 所有长度为 0 和长度为 1 的字符串都被驻留.
- 字符串在编译时被实现 ('wtf' 将被驻留, 但是 ''.join(['w', 't', 'f'] 将不会被驻留)
- 字符串中只包含字母,数字或下划线时将会驻留. 所以 'wtf!' 由于包含 ! 而未被驻留. 可以在这里找到 CPython 对此规则的实现.
5.From filled to None in one instruction.../从有到无...
>>> print(some_list)
None
>>> print(some_dict)
None
为啥会这样,是不是很奇怪,some_list明明已经append了然后赋值给自己了为啥还是None呢。
大多数修改序列/映射对象的方法, 比如 list.append, dict.update, list.sort 等等. 都是原地修改对象并返回 None. 这样做的理由是, 如果操作可以原地完成, 就可以避免创建对象的副本来提高性能
6.A tic-tac-toe where X wins in the first attempt!/一蹴即至!
第一个print我们输出的是:
[['', '', ''], ['', '', ''], ['', '', '']]
第二个print我们输出的是:
[['X', '', ''], ['X', '', ''], ['X', '', '']]
奇怪了,我们我们有没有赋值过3个 "X" 呢?
说明:
当我们初始化 row 变量时, 下面这张图展示了内存中的情况。
而当通过对 row 做乘法来初始化 board 时, 内存中的情况则如下图所示 (每个元素 board[0], board[1] 和 board[2] 都和 row 一样引用了同一列表.)
我们可以看到其实这3个的内存空间是同一地址
print (id(board[0][0]))
4514093072
print (id(board[1][0]))
4514093072
print (id(board[2][0]))
4514093072
7.When True is actually False/假亦真时真亦假
说明:
- 最初, Python 并没有 bool 型 (人们用0表示假值, 用非零值比如1作为真值). 后来他们添加了 True, False, 和 bool型, 但是, 为了向后兼容, 他们没法把 True 和 False 设置为常量, 只是设置成了内置变量.
- Python 3 由于不再需要向后兼容, 终于可以修复这个问题了, 所以这个例子无法在 Python 3.x 中执行!
8.让人困惑的else
>>
>>> some_list = [1, 2, 3, 4, 5]
>>> does_exists_num(some_list, 4)
Exists!
>>> does_exists_num(some_list, -1)
Does not exist
这个else还好理解,我们搜索some_list如果找到,则break 退出,如果找不到最后运行else里面的语句!
如果这样理解,那么下面的else就更难理解了!
>>
Try block executed successfully...
说明:
- 循环后的 else 子句只会在循环没有触发 break 语句, 正常结束的情况下才会执行.
- try 之后的 else 子句也被称为 "完成子句", 因为在 try 语句中到达 else 子句意味着try块实际上已成功完成.
限于篇幅,Python有这么多隐含的技巧和特性,真的让多年的老司机都叹为观止。不过随着Python3.x版本的越来越问题,这些以前的梗慢慢的在优化。
到了此刻我想大家对Python的特性有一些了解了吧~ 小编这里有一套从入门到精通的Python学习资料,不知道大家喜不喜欢,今天就给大家分享一下吧! 让大家也有个学习的方向,为人工智能奠定一下坚实的基础,话不多说,上干货: