51个Python鲜为人知的秘密特性,老司机看完都惊叹不已

论坛 期权论坛 期权     
菜鸟学Python   2019-6-29 20:44   2254   0


Python真的很奇妙,目前是最火的语言。语法简单,功能强大,我学Python已经好多年了,从2.6的时代一直到现在的3.8,算算也是老鸟了。今天看了一个网站,上面讲了很多Python鲜为人知的特性,看完我也是大开眼界,不得不说,Python真实博大精深!




1.Midnight time doesn't exist?/不存在的午夜



>>
  1. ('Time at noon is', datetime.time(12, 0))
复制代码

midnight_time 并没有被输出.在Python 3.5之前, 如果
  1. datetime.time
复制代码
对象存储的UTC的午夜时间(译: 就是
  1. 00:00
复制代码
), 那么它的布尔值会被认为是
  1. False
复制代码
. 当使用
  1. if obj:
复制代码
语句来检查
  1. obj
复制代码
是否为
  1. null
复制代码
或者某些“空”值的时候, 很容易出错.


2.Time for some hash brownies!/是时候来点蛋糕了



>>
  1. >>> some_dict[5.5]
  2. "Ruby"
  3. >>> some_dict[5.0]
  4. "Python"
  5. >>> some_dict[5]
  6. "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值是一样的




[h3]说明:[/h3]
  • 这些行为是由于 Cpython 在编译优化时, 某些情况下会尝试使用已经存在的不可变对象而不是每次都创建一个新对象. (这种行为被称作字符串的驻留[string interning])
  • 发生驻留之后, 许多变量可能指向内存中的相同字符串对象. (从而节省内存)
  • 在上面的代码中, 字符串是隐式驻留的. 何时发生隐式驻留则取决于具体的实现. 这里有一些方法可以用来猜测字符串是否会被驻留:
    • 所有长度为 0 和长度为 1 的字符串都被驻留.
    • 字符串在编译时被实现 (
      1. 'wtf'
      复制代码
      将被驻留, 但是
      1. ''.join(['w', 't', 'f']
      复制代码
      将不会被驻留)
    • 字符串中只包含字母,数字或下划线时将会驻留. 所以
      1. 'wtf!'
      复制代码
      由于包含
      1. !
      复制代码
      而未被驻留. 可以在这里找到 CPython 对此规则的实现.
[h2]5.From filled to None in one instruction.../从有到无...[/h2]
  1. >>> print(some_list)
  2. None
  3. >>> print(some_dict)
  4. None
复制代码
为啥会这样,是不是很奇怪,some_list明明已经append了然后赋值给自己了为啥还是None呢。

大多数修改序列/映射对象的方法, 比如
  1. list.append
复制代码
,
  1. dict.update
复制代码
,
  1. list.sort
复制代码
等等. 都是原地修改对象并返回
  1. None
复制代码
. 这样做的理由是, 如果操作可以原地完成, 就可以避免创建对象的副本来提高性能

6.A tic-tac-toe where X wins in the first attempt!/一蹴即至!



第一个print我们输出的是:
[['', '', ''], ['', '', ''], ['', '', '']]
第二个print我们输出的是:
[['X', '', ''], ['X', '', ''], ['X', '', '']]
奇怪了,我们我们有没有赋值过3个 "X" 呢?
说明:
当我们初始化
  1. row
复制代码
变量时, 下面这张图展示了内存中的情况。


而当通过对
  1. row
复制代码
做乘法来初始化
  1. board
复制代码
时, 内存中的情况则如下图所示 (每个元素
  1. board[0]
复制代码
,
  1. board[1]
复制代码
  1. board[2]
复制代码
都和
  1. row
复制代码
一样引用了同一列表.)


我们可以看到其实这3个的内存空间是同一地址
  1. print (id(board[0][0]))
  2. 4514093072
  3. print (id(board[1][0]))
  4. 4514093072
  5. print (id(board[2][0]))
  6. 4514093072
复制代码
7.When True is actually False/假亦真时真亦假



说明:
  • 最初, Python 并没有
    1. bool
    复制代码
    型 (人们用0表示假值, 用非零值比如1作为真值). 后来他们添加了
    1. True
    复制代码
    ,
    1. False
    复制代码
    , 和
    1. bool
    复制代码
    型, 但是, 为了向后兼容, 他们没法把
    1. True
    复制代码
    1. False
    复制代码
    设置为常量, 只是设置成了内置变量.
  • Python 3 由于不再需要向后兼容, 终于可以修复这个问题了, 所以这个例子无法在 Python 3.x 中执行!

8.让人困惑的else


>>
  1. >>> some_list = [1, 2, 3, 4, 5]
  2. >>> does_exists_num(some_list, 4)
  3. Exists!
  4. >>> does_exists_num(some_list, -1)
  5. Does not exist
复制代码
这个else还好理解,我们搜索some_list如果找到,则break 退出,如果找不到最后运行else里面的语句!

如果这样理解,那么下面的else就更难理解了!

>>
Try block executed successfully...

说明:
  • 循环后的
    1. else
    复制代码
    子句只会在循环没有触发
    1. break
    复制代码
    语句, 正常结束的情况下才会执行.
  • try 之后的
    1. else
    复制代码
    子句也被称为 "完成子句", 因为在
    1. try
    复制代码
    语句中到达
    1. else
    复制代码
    子句意味着try块实际上已成功完成.



限于篇幅,Python有这么多隐含的技巧和特性,真的让多年的老司机都叹为观止。不过随着Python3.x版本的越来越问题,这些以前的梗慢慢的在优化,有兴趣的同学赶紧戳 阅读原文链接来看一下这51个特性。

往期热门:
99%的Python程序员都不知道的秘密
用30行代码|搭建一个提醒《权游》剧集系统


分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:160
帖子:32
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP