Py学习  »  Python

推荐 + 赠书 《Python 3学习笔记(上卷)》

Python之美 • 6 年前 • 664 次点击  

前言

「如何学习编程」每个人都有自己的答案,在我初学Python的时候,我就非常关注大神们的学习方式和成长之路。工作这么些年过来,我发现大家入门和学习的共同点非常统一:读书、看源码、高频率的实践和动手,对于现在的同学还可以选择看视频。

在我的印象里面,大神TJ Holowaychuk的学习方法让我记忆深刻,大概4-5年前我看过一个介绍,但是找不到印象里的那篇了,只找到了这篇TJ Holowaychuk是怎样学习编程的?(https://zhuanlan.zhihu.com/FrontendMagazine/19572823)。TJ的学习方法很特别:

也不读书,从不去听课,我就是去阅读别人的代码,并搞清楚那些代码是如何工作的。

而《Python 3学习笔记(上卷)》(http://t.cn/RE5JVdj, 也可以在文末点击「阅读原文」到图书详情页)作者雨痕在我印象里面就是这样通过阅读CPython源代码来学习Python的。

qyuhen/book

雨痕前辈从1996年开始从事计算机软件开发工作,从2006年接触Python,他的 qyuhen/book 在2013年的时候就已经非常知名了。这个项目下是除了Python笔记,还有Go,C方面的学习笔记。

第一次阅读《Python学习笔记》就被它的内容吸引,虽然只是作者的学习笔记,但是依然不影响对于学习Python的开发者的意义,我觉得这个笔记有2个显著的特点:

  1. 从解释器和CPython源码实现的角度剖析语言语法

  2. 通过在交互环境中的实验去证明和验证细节,获得结论

可以说这本书对13年的我来说,有很大的帮助。当然这个笔记里面还有一些有意思的点,我在14年的 Python高级编程 分享中PPT一上来就引用了这个笔记中提到的怎么让Python支持end:

  1. __builtins__.end = None

  2. def test(x):

  3.    if x > 0:

  4.        print "a"

  5.    else:

  6.        print "b"

  7.    end

  8. end

  9. def main():

  10.    test(1)

  11.    print('I can use end!')

  12. end

嗯,这不是ruby。其实能这么写的根本原因就是end被解释成了None,写成什么都可以:

  1. __builtins__.endif = None

  2. def test(x):

  3.    if x > 0:

  4.        return True

  5.    endif

  6. test(1)

之后雨痕老师的《Go语言学习笔记》出版了,但是《Python学习笔记》却没有动静,我既有失望也满怀期待,想必没有考虑出版它是由于这个笔记是针对 Python2.7 的。

但是不要紧,《Python 3学习笔记(上卷)》来了。

荐书

关注我的同学应该都知道我是不愿意参与荐书的,我得对订阅者负责。我没看过的、觉得不好的书我是不可能推荐给别人的。

目前我正式的荐书只有《流畅的Python》(http://t.cn/RE5JdMk)和平时在群里说到的《python编程 从入门到实践》(http://t.cn/RE5JsHZ),《Python 3学习笔记(上卷)》(http://t.cn/RE5JVdj)是我推荐的第三本书。节前就收到了样书,刚刚读完,给大家分享一下读后感。

本书的特点

  1. 书中内容基于目前最新的Python 3.6版本,书中提到的一些最新的Python内容还很少有中文书或者博客来介绍。在2018年这个节点,如果一本新书还在讲Python 2,反正我是不会买了。

  2. 同样是从解释器和CPython源码实现的角度剖析语言语法。市面上大部分的教程都是在告诉你应该怎么用,但是背后隐藏的细节和原理却很少提及,这本书对这些并不避讳,而更像是想弄清楚解释器执行的流程和细节。尤其是在「解释器」章节里面除了从源码上分析GIL,还有内存分配、垃圾回收和Python执行过程的方面的内容。

  3. 配图丰富、简单易懂。同作为图书作者,我很了解做配图是一件很耗时辛苦的事情,既要对配图的内容理解非常深刻,也要让它直观好懂是很难的,这本书这点做的就不错。

  4. 通过在交互环境中的实验去证明和验证细节,获得结论。这是我非常喜欢的方式,作为一个读者用这样的方式学习知识是很轻松愉快的

  5. 概念定义深刻准确。雨痕老师的编程经验非常丰富,对Python也很熟悉,对一些知识点的定义和理解非常好。我举2个例子:

包和模块

有多少人不能清晰区分他俩?我看到很多同学用这2个词的时候很随意,这本书里面是这么说的:「模块( module) 是顶层代码组织单元,其提供大粒度的封装和复用... 如果说模块用于组织代码,那么包就是用来组织模块的...」,总结非常到位。

借助生成器切换执行功能,改善程序的结构设计

我举书中列出的2个例子,第一个是生产消息模型:

  1. def consumer():                                                                                          

  2.    while True:                                                                                          

  3.        v = yield                                                                                        

  4.        print(f'consume: {v}')                                                                          

  5. def producer(c):                                                                                        

  6.    for i in range(10, 13):                                                                              

  7.        c.send(i)                                                                                        

  8. c = consumer()                                                                                          

  9. c.send(None)                                                                                            

  10. producer(c)                                                                                              

  11. c.close()                                                                                                


当然作者也提到如果有多个消费者或者数据处理时间较长,还是建议使用专业的并发方案。第二个是消除回调。我们先看看异步回调的模式:

  1. import time                                                                                              

  2. import threading                                                                                        

  3. def target(request, callback):                                                                          

  4.    s = time.time()                                                                                      

  5.    request()                                                                                            

  6.    time.sleep(2)                                                                                        

  7.    callback(f'done: {time.time() -s }')                                                                

  8. def request():                                                                                          

  9.    print('start')                                                                                      

  10. def callback(x):                                                                                        

  11.    print(x )                                                                                            

  12. def service(request, callback):                                                                          

  13.    threading.Thread(target=target, args=(request, callback)).start()                                    

我一直不喜欢回调,这种接口设计的方式会让代码和逻辑分散开,维护性很差。如果使用生成器怎么做呢?

  1. def request():                                                                                          

  2.    print('start')                                                                                      

  3.    x = yield                                                                                            

  4.    print(x)                                                                                            

  5. def target(fn):                                                                                          

  6.    try:                                                                                                

  7.        s = time.time()                                                                                  

  8.        g = fn()                                                                                        

  9.        g.send(None)                                                                                    

  10.        time.sleep(2)                                                                                    

  11.        g.send(f'done: {time.time() -s }')                                                              

  12.    except StopIteration:                                                                                

  13.        pass                                                                                            

  14. def service(fn):                                                                                        

  15.    threading.Thread(target=target, args=(fn,)).start()                                                  

  16. service(request)                                                                                        

这样就不需要callback性质的额外参数了,通过yield让程序逻辑看起来是串行的。

我要强调一下:这本书并不是适合入门,它假定读者已经有一定的编程和Python基础 。所以更适合已经熟悉Python语言语法,使用Python写过程序的开发者,如果你正准备迁移Python 2的代码到Python 3.6这本书就更值得看一看了。

在上个月发布的《爱湃森 2017年度Python榜单》中,我也把这本书放到了 2018年最值得期待的国内出版的Python书籍的第二位(那会我还没拿到样书),现在看来这本书也物超所值,对我这种Python老手来说,看书获取新知识的几率已经不高,但是从这本书里面我还是收获了很多。我举几个印象深刻的例子:

  1. 池化。之前没了解过,就是相同名字可能会重复出现在不同的名字空间里,就有必要共享实例,这样节约内存,也省去了创建新实例的开销,所以Python实现了字符串池。

  2. 自定义异常类的名字。我以前自定义异常的名字比较随意,XyzException或者XyzError通常有点看心情或者仿之前名字格式,这本书这样说的「内置异常多以Error结尾,但建议以Exception、Error后缀区分可修复异常和不可修复异常」,我觉得说得对...

  3. SimpleNamespace。之前我想快速的构建一个结构化的实例会用namedtuple,但是缺点是它构建出来的是一个类型:

  1. In [5]: Point = namedtuple('Point', ['x', 'y'])

# 构建出来的是一个类,而且传递参数的效果也不直观,field_names需要是一个列表或者空格分割的字符串,不方便                                                        

  1. In [6]: p = Point(1, 2)  # 我还得实例化一下Point才能用                                                  

  2. In [7]: p.x, p.y                                                                                        

  3. Out[7]: (1, 2)                                                                                                                                                                                                                                                                           

这样不方便,SimpleNamespace就可以直接创建实例:

  1. In [8]: from types import SimpleNamespace                                                                

  2. In [9]: p = SimpleNamespace(x=1, y=2)                                                                    

  3. In [10]: p.x, p.y                                                                                        

  4. Out[10]: (1, 2)                                                                                                                                                                        

这样用起来就方便多了。

上述这几点算是我的读书笔记,详细的还得看书中原文哦。

希望国内能出现越来越多的好书!有能力有想法的同学,可以私信我帮你联系出版社哟

赠书

我向电子工业出版社谋了5本《Python-3学习笔记(上卷)》福利给大家。这次在移动端的抽奖用「抽奖助手」小程序,关注本公众号之后,长按下图,在弹出框中「选择识别图中的小程序码」进入抽奖页面即可:



今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/CDRrZjt2PS
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/7659
 
664 次点击