Follower me on GitHub

15年11月19日,我打开了一个不常用的邮箱,看到了2天前编辑给我发的邮件,问我想不想写本Python相关的书。

那个时候正是我的黑暗期,一个专注写代码几年的人开始做一些管理工作,一方面要学习,要转换思想,一方面心情也不好,每天就是在处理各种杂事,别说是技术进步了,哪怕把事情考虑周全的时间都没有。每天 一个人当成2个人来用,操碎了各种心,很累。

对于我这种写代码的,甚至都不善于逗小孩笑的程序员,总想给女儿点不一样的礼物。希望我带给她一些精神上的帮助。看到邮件的一瞬间,我就想象女儿长大之后,对其他人说:喏,那是我爸写的书,给我做生日礼物…

就是这2个理由。我决定写这本书。

12月4日,我提交的大纲顺利通过审核。

12月6日,CODE真的开源了,喜大普奔。我靠着情怀坚持做完了。CODE那段时间上了Github Trending,我很欣慰,虽然一切都太晚了。

接下来的20多天里面,我正忙着弄CODE开源的事情,只是在构思这本书都要有什么内容,并没有下笔。我天真的觉得同时可以把2件事做好,但是后来发现时间完全是不够的,所以我停止的CODE的进一步的迭代。其他的原因是豆瓣已经决定迁移到Github企业版,我一个人并无力改变什么,如果公司自己都不用,那开源的就没有意义了。再则我也受到了厂内很多质疑和嘲讽,心碎。

一些写书的介绍可以看这篇专栏《写一本技术书籍》,并建议大家关注这个专栏,近期将有一大波文章要在专栏发呢。

专栏有些结论先发出来:

  1. 开始写书是在圣诞节左右,结束时间是8月15日。也就是差不多240天。
  2. 写这本书能让我挣2W多,嗯,时薪23块钱。

现在开始介绍这本书。

谁应该看本书

看书名可知这是一本Web开发相关的书,但事实上里面有大概一半的内容其实是Python工程师都能用到的。我对书的受众的理解是:

  1. Web开发者
  2. 运维开发
  3. 想提高Python技能的开发者
  4. 其他想了解Python Web开发的其他开发者

需要注意,阅读本书需要有一定的Python基础,因为书中没有基础语法教程,如果你之前没用Python写过程序阅读起来可能会受到影响。

为什么值得看

我阅读过大量和Python有关的纸质书和开源图书,渐渐学到了很多控制自己“剁手”买书的方法。我来分析一下为什么你值得拥有本书。:)

为什么要买书来看?我认为不外乎两个原因:有趣和能学到东西。技术书肯定不会太有趣,那么最重要的就是能学到东西。市面上Python相关的书相当多,但是有些内容陈旧或者不符合国情,经常能看到并非开发第一线的人写或者翻译的书,这些书显然价值就要低一些;其次是同质化和向入门级别靠拢,我个人认为市面上关于Python入门或者教授语法知识的书不少,而再深入一点的就很匮乏了。

本书有几个特点: 第一,使用了当前主流和前瞻性的技术,如Docker、Ubuntu 16.04 LTS、Cython、CFFI、Py.test、asyncio、IPython 5.0 LTS等,书中一部分内容是在Python 3下完成的。本书中全部工具都使用当前最新版,能保证在相当长的时间内书中的内容都不会过时。 第二,笔者在国内应用Python最大的豆瓣网做产品开发,一直在第一线写代码,大量例子和经验都是根据实际经验出发的。 第三,笔者非常关注Github和Python社区,会第一时间了解到新的趋势和思想,并在书中体现。举个例子,代码检查工具pep8已经在Guido van Rossum的要求下改名为pycodestyle了。

叔本华在《人生的智慧》中说过一段话,大意是人要么庸俗,要么孤独。笔者认为这个道理在阅读上面也成立:读什么样的书,就会逐渐成为什么样的人。本书提供了很多笔者在其他书中没有看到过的思考方式和Python的用法,这也是本书存在的意义。

本书涵盖的内容

第一章.「初识Python Web开发」

将回答Python工程师关心的如下3个问题:

  1. 为什么应该选择Python作为Web开发语言?
  2. 在Python 2和Python 3之间如何选择?
  3. 在这么多的Python Web框架中哪些是主流的,它们的特点是什么,该如何选择?

第二章. 「Web开发前的准备」

  1. 环境的准备,以便读者能够使用Vagrant或者Docker提供的Ubuntu环境运行书中的例子。
  2. 介绍包管理工具pip及一些高级用法。
  3. 实现PYPI的缓存代理和完全镜像。
  4. 使用virtualenv及其扩展实现虚拟环境管理。

第三章. 「Flask Web开发」

  1. 通过多个应用例子了解Flask框架使用的一些精髓。
  2. 介绍目前最流行的模板引擎Jinja2和Mako的使用,以及实践总结和做选择时的建议。
  3. 通过一些例子让读者熟悉MySQLdb的使用,并演示如何和Flask应用集成。
  4. 通过源码帮助读者理解Flask的上下文设计,并演示大型应用中使用上下文钩子的例子。
  5. 通过一个真实的案例学以致用。先分析需求,接着从零开始实现一个文件托管应用。

第四章. 「Flask 开发进阶」

  1. Flask的信号机制。利用信号可以实现一部分的业务解耦。
  2. Flask的一些常用、主流的扩展,如Flask-Script、Flask-DebugToolbar、Flask-Migrate、Flask-WTF、Flask-Security、Flask-RESTful、Flask-Admin和Flask-Assets。每个扩展都包含至少一个完整的真实例子。
  3. Flask的依赖库Werkzeug的使用。

第五章. 「REST和Ajax」

  1. 帮助读者理解REST。
  2. 学习如何设计一个合理、好用、符合标准的API。
  3. 使用jQuery和fetch分别完成一个前后端交互的Ajax应用。

第六章. 「网站架构」

  1. 了解WSGI协议。
  2. 主流的Python应用服务器的特点和使用方法。
  3. 使用Nginx和Python应用服务器部署Flask应用。
  4. 介绍豆瓣开源的Libmc和豆瓣常用的缓存使用方式。
  5. 举例说明Redis的几个应用场景,包含使用MessagePack进行序列化和反序列化工作。
  6. 介绍使用NoSQL的原因和场景。
  7. 使用pymongo,并用Mongoengine重构文件托管服务的模型。
  8. MongoDB索引、高可用和分片的经验。
  9. 以豆瓣的基础架构为原型,展示主流大型网站的架构模式,并详细介绍相关重要模式,以及Web前端的性能优化经验。

第七章. 「系统管理」

  1. 使用Supervisor管理进程。
  2. 使用Fabric进行应用部署。
  3. 通过部署Redis了解配置管理工具SaltStack和Ansible。
  4. 使用Psutil获取系统CPU、内存、硬盘和网络等信息。
  5. 配图演示Sentry的安装和收集错误信息的效果。
  6. 使用StatsD、Graphite、Diamond和Grafana搭建Web监控,并介绍常见的运维监控工具及其主要应用场景。

第八章. 「测试和持续集成」

  1. 介绍和使用Python内置测试模块unittest和doctest。
  2. 介绍和使用第三方测试工具py.test和mock。
  3. 深入持续集成,并通过Buildbot实际地对一个Github项目进行集成。

第九章. 「消息队列和Celery」

  1. 使用Beanstalkd。
  2. 解释AMQP,深入理解RabbitMQ,介绍RabbitMQ插件系统,RabbitMQ集群的故障转移方法等。
  3. 介绍Celery的架构,运行起一个真实的应用,在Flask应用中使用Celery等功能。
  4. 深入Celery,介绍Celery的依赖及独立用法、Worker管理、监控等高级功能。
  5. 笔者总结的一些Celery实践经验。

第十章. 「服务化」

  1. 为什么需要服务化。
  2. 使用Thrift对文件托管服务改造。
  3. 介绍豆瓣服务化实践——PIDL的起因、基本原理和基本架构。

第十一章. 「数据处理」

  1. 使用纯Python代码实现MapReduce功能。
  2. 配置DPark环境,深入了解DPark,演示如何用DPark对业务日志进行PV和UV的分析。
  3. 通过发送带有样式和附件的邮件,创建包含带样式和Sparkline图表的xlsx文件,以及创建包含多工作表和4. 图表的xlsx文件这三个有用的例子,展示笔者对数据报表的理解和运用。
  4. 基于数据报表中的数据,用Pandas进行分析和展示。

第十二章. 「帮助工具」

  1. 解释为什么应该使用IPython,配置IPython、调试复杂代码、并行计算等。
  2. 介绍Jupyter Notebook的用途,配置Jupyter Notebook,在Notebook里使用Echarts、自定义JavaScript和CSS样式等高级功能。
  3. 介绍常用的获得Linux服务器相关情况的工具。
  4. 介绍性能测试工具Boom和tcpcopy,并演示如何搭建一个tcpcopy环境。
  5. 介绍分析Python程序性能瓶颈的工具。
  6. 演示如何定制基于IPython的交互解释环境。
  7. 演示豆瓣东西在2014年双十一进行的Jupyter Notebook实践。

第十三章. 「Python并发编程」

使用多线程、多进程、Gevent、Future和asyncio这五种方式实现一个爬取微信公众号的抓取。其中还揭秘了一些写爬虫的经验。尤其是告诉读者如何选择并发方式。

第十四章. 「Python进阶」

  1. 介绍errno、subprocess、contextlib、glob、operator、functools、collections模块的使用方法。
  2. 笔者对《Python之禅》的理解。
  3. 笔者总结的一些Python实践经验,并列举了两篇最佳实践的文章。
  4. 介绍一些Python 3的有用功能,并移植到Python 2。
  5. 通过真实的例子演示如何使用CFFI/Cython编写Python扩展,并对比二者的执行效率。
  6. 演示使用PyObjC发送通知的例子,让开发者收到的通知更有针对性。

第十五章. 「Web开发项目实践」

  1. 介绍笔者的Web项目开发流程和经验。
  2. 介绍开源的代码质量保证工具,以及豆瓣的一些质量保证实践。
  3. 使用AST对真实的业务逻辑做静态检查,实现业务流程的检查。
  4. 谈谈代码评审的意义和实际经验。

PS: 本书还有其他惊喜,我就不打广告了。感谢大家支持,也希望通过本书能让你有所收获。

前言

持续集成(Continuous Integration)已经是公认的保证产品质量和开发快速迭代的开发实践了。 目前常见的CI服务器有2种:

  1. Jenkins。 Jenkins是一个用Java编写的开源的持续集成工具, 它有丰富的插件和完善的API, 但实际工作中发现它不太稳定, Python和前端工程师很难对其进行二次开发, 页面和功能也有些陈旧。
  2. Travis CI。 一个针对Github的云服务平台, 只对开源项目提供免费的CI服务。

本篇博客将给大家介绍一个新的持续集成工具Strider。 一个使用Node.js开发的、 开源的持续集成和发布服务器。 目前它已经支持Github、 Bitbucket、 Gitlab等平台, 支持Python、 Ruby、 Node.js和其他自定义的应用。 虽然它使用常见了bootstrap, 但是页面效果还是很不错的。

在使用之前, 我们先创建一个Github开发者应用, 内容如下图:

然后在Github上创建一个用来测试的项目dongweiming/tola

使用Strider集成

使用最新版的Node.js:

❯ wget https://nodejs.org/dist/v4.4.2/node-v4.4.2.tar.gz
❯ tar zxf node-v4.4.2.tar.gz
❯ cd node-v4.4.2
❯ ./configure && make && sudo make install

安装Strider:

❯ git clone https://github.com/Strider-CD/strider
❯ cd strider
❯ npm install  # 安装依赖包

Strider配置项很多, 可以在Strider目录下添加.striderrc文件:

❯ cat .striderrc
{
"db_uri": "mongodb://dongwm:dongwm@ds015720.mlab.com:15720/strider-dongwm",  # 我的VPS不够1G内存, 不能安装MongoDB, 使用 MongoLab的免费服务来测试
"smtp_host": "smtp.mailgun.org",  # Mailgun提供每天可发送300封邮件的免费服务, 我们用它来测试
"smtp_user": "postmaster@sandboxabe8d2f42ac8424fa8dd4c5ab1f1d92b.mailgun.org",
"smtp_pass": "4e0c2880f7aaf6c1b5f39bb88acabee1"
}

创建管理员用户:

DB_URI=mongodb://dongwm:dongwm@ds015720.mlab.com:15720/strider-dongwm node bin/strider addUser

启动服务, 需要上面创建的开发者应用的APP_ID和APP_SECRET(如果使用Github企业版, 需要设置PLUGIN_GITHUB_API_DOMAIN和PLUGIN_GITHUB_API_ENDPOINT):

export SERVER_NAME=http://VPS:3000
export PLUGIN_GITHUB_APP_ID=1a7bcf97d84c938bdbe8
export PLUGIN_GITHUB_APP_SECRET=316947cbe6a85e295dcd2346f272f7844aea87cd
NODE_ENV=production npm start

访问http://VPS:3000/login, 使用之前创建的管理员用户登录。 目前还没有配置项目:

Strider默认开启了Github、 Bitbucket、 Gitlab插件。 点击Github按钮来集成Github支持(也可以直接使用如下地址访问http://VPS:3000/auth/github):

点击Authorize application按钮, 输入有权限的Github账号密码。 验证后会跳回Strider的项目页面下。

找到项目tola, 点击项目右侧的Add

接下来选择项目类型, 这里选择Python, Strider会做一些初始设置。

Strider会自动给项目添加一个Webhook。 打开https://github.com/dongweiming/tola/settings/hooks可以看到:

访问插件管理页面:http://VPS:3000/admin/plugins, 我们需要安装Github Status这个插件, 点击后面的Install。

访问http://VPS:3000/dongweiming/tola/config/tab-plugins激活邮件通知和Github状态插件, 需要把Email NotifiterGitHub Status拖拽到左面。

进入http://VPS:3000/dongweiming/tola/config/plugin-emailnotifier页面勾选Always send notification emails.

现在当tola项目发生Pull request、 Push等事件时就会自动触发这个集成测试了。 项目结果页面是http://VPS:3000/dongweiming/tola。 构建成功的效果如下:

构建失败的效果如下:

同时, 在Github的Pull request页面也会显示集成结果:

打开QQ邮箱就可以看到集成结果的邮件了:

Strider自带发送Slack通知的插件, 而且Strider插件非常容易定制, 可以定义更多的插件支撑业务需要。

前言

写这个评注系统是因为最新写书, 想找个更顺畅的和编辑沟通的方式, 提高工作效率。 学Django的同学应该都访问过: http://djangobook.py3k.cn/ , 它和Djangobook官网 有个很重要的功能: 评注系统。在这里先向VCC致敬, 虽然很久没有继续维护,但是这个评注的功能还是很不错的。

我也翻了Djangobook的Git提交记录, 没有找到实现的方式。 而且最重要的是, 它是通过ReStructuredText生成的静态页面, 不符合我的需求。所以有了今天说的Aiglos

可以看Heroku上的Demo看看效果, 其中的文档使用了 https://github.com/GitbookIO/markdown

功能

  1. 在线浏览渲染的本地Markdown文件。
  2. 提供 http://djangobook.py3k.cn/2.0/ 那样的评注系统。
  3. 评注支持Markdown语法。

使用的技术

Flask: Web框架 Mako: 模板语言 Flask-Mako: Mako支持的Flask扩展 Flask-SQLAlchemy: SQLAlchemy的Flask扩展 mistune: Markdown渲染 cython: Python转化到C的编译器, 可以让mistune渲染更快

使用说明

❯ git clone https://github.com/dongweiming/aiglos
❯ cd aiglos
❯ virtualenv-2.7 venv
❯ source venv/bin/activate
❯ pip install -r requirements.txt
❯ touch local_settings.py  # 增加BOOK_DIR (Markdown文件存放目录), SQLALCHEMY_DATABASE_URI等配置
❯ gunicorn -w 3 run:app -b 0.0.0.0:8000

最近参考linty_fresh实现了一个webhook服务, 提PR自动检查Flake8, 当有代码风格问题的时候,并在对应位置发评论

项目地址是: gandalf

在公司内的Github企业版上, 已经用了一段时间, 比较稳定. 现在开源出来, 有兴趣的可以拿去^.^

这个项目也是我的学习asyncio的练手作品, 吐槽下Type Hints让代码显的好丑哇…

项目知识点

  1. Python3: 项目需要使用Python3, 建议使用Python3.5
  2. rq: 工作中有一些项目的版本库很大, 实际的检查时间也会长一些, 为了保证应用解耦和更好的提供支持, 使用rq作为任务队列
  3. aiohttp: 基于asyncio的http库, 用来调用github api, 获取对应pr信息
  4. pygit2: 使用官方模块实现Python版本的git版本控制功能, 它的安装比较麻烦, 但是官方文档讲的很清楚
  5. Flask: 作为webhook的服务框架

来几张截图看个效果:

配置

 cat gandalf/config.py
WORK_DIR = '/tmp/repositories'  # 设定克隆的项目版本库代码存放位置
FLAKE8_EXECUTABLE = '/usr/local/bin/flake8'  # 这个项目时Python3的,但是目前大部分应用还是Python2的, 所以需要Python2版本的flake8
HOST = '0.0.0.0'
PORT = 8080
DEBUG = False
REPORT_NO_MATCHING = False  # 没有在diff列表的文件的错误是否也报告
GITHUB_URL = 'http://github.com/'  # 行尾要加反斜杠
GITHUB_API_URL = 'https://api.github.com'  # 行尾不要加反斜杠
REPORT_CLOSEST = False # 错误出现在PR列出的文件中, 但是修改并不是此次PR中的diff里面是否报告
COMMENT_HEADER = ''  # 上述截图出现的emoji头部就是指定它, 我的设置是`COMMENT_HEADER = ':sparkles:Subject Bot:sparkles:'`


try:
    from local_settings import *
except ImportError:
    pass

配置webhook

需要在github的项目/组织设置页,找到Webhooks, 然后Add webhook

  1. Payload URL输入 http://192.168.1.1:28030/api/hooks # 或者你跑起来web服务的地址
  2. 选择事件 ,Let me select individual events. 然后勾选Pull Request

如图:

Enjoy it

应某出版社约, 最近一直在写一本Python Web开发的书. 暂时不发大纲全部的章节,主要涵盖如下方面的内容:

  1. 使用Python从零开始做一个完善的项目
  2. 源码级别分析产品过程中的各种知识点
  3. 站在运维,运维开发的角度讲解现在互联网Web应用的的方方面面
  4. 排错, 优化, 设计项目等

我清晰的知道都写些什么, 但是担心最后遗漏读者们有兴趣,关心的一些方面的内容, 特写本文. 本博客的读者如果有想法和建议, 欢迎和我交流.

开源了, 开源了

喜大普奔.

欢迎围观试用: CODE

再来一遍 CODE

想直接看效果的可以看 这里 或者拉到最下面.

可能很多人有点诧异, CODE不是已经开源了么? 是的, 2014年2月14日CODE的早期版本就开源到了github. 但是后来由于很多原因没有在做下去, 今天, 它真的开源了.

让我坚持下来的也是我想给外界看到豆瓣工程师文化的结晶, 这是一种情怀, 今天我想说说我和CODE的故事

CODE的意义

CODE为什么开源: 希望更多的人可以使用 CODE,希望更多的人可以一起开发 CODE。 - Code Team

市面上有gitlab, 有github企业版. 我们折腾一个这样的东西有什么意义呢? 以下是我的看法.

  1. CODE是一款豆瓣工程师自发组织, 基于我们自己的需要做出来的. 它是互联网公司程序员的需要而产生的, CODE也曾经给github的同仁们演示, 获得了很高的赞誉.
  2. 它并不是github的python克隆版, 但是有些地方却是和github殊途同归.
  3. 当产品发展到一定地步, 对这个版本控制工具会有更多的定制化需求, 这个时候会需要二次开发. 假如你是个ruby开发很多的公司, 用gitlab也不算个问题. 但是假如大家用非ruby的语言为主, 那么就很痛苦. ruby虽然在配置管理, web开发上面有一席之位, 但是没有python这么普遍. 同事们的参与局限性就多了很多.
  4. 假如你所在公司是python系, 或者爱好python系的, 那么CODE真的是一个很不错的选择. 它是永远免费的, 它是由国内python最大应用公司的工程师们开发, 质量有保证. 看代码的过程中也能学习到一些python的技巧, 豆瓣的玩法, 了解豆瓣的开发流程.
  5. 我一直觉得轮子是需要造的, 这个过程你能有造轮子的乐趣, 能力得到更多的提高, 而一直在用其他人的东西那么永远只会停留在这个程度上.
  6. 用CODE, 看CODE代码的时候, 仿佛可以看到那帮有情怀, 有工程师文化的同学们在讨论需求, code review… 我一直认为这种关系和友谊才是最好的团队具有的

情怀

好吧, 啥是情怀呢?

情怀就是以心灵的满足而不是功利的得失作为自己的行为标准的一种品质。 一件没什么用的事,还是要去做,也许只因为我喜欢,也许只因为它看起来很美 – 知乎@宋老末

「我坚信程序员都是有情怀的. 」

我决定继续这件事, 到现在已经4个月有余. 这个过程里面经历蛮多, 比如我经历着从技术转型做管理, 部门问题多多, 人员也在我强力介入下也流动蛮大的 -。-; 我也要花很大的精力陪女儿; 我一直也在不断的给自己充电, 我现在也要开始写书了… 做了TL, 唯一的感觉就是时间不够用, 我是个蛮有洁癖的人, 以前做普通工程师的时候按期完成我职责范围内的就好了, 现在责任大了, 看着产品线的sentry里那么多的报错, 看着Trello里面堆积那么多的card还没有机会做… 尤其在我使用一种新的管理风格有关, 让我倍敢压力, 非常辛苦.

要不是xTao不断催促, 可能还要拖期.

是什么支撑我的情怀?

除了眼前的苟且,还有诗和远方 - 知乎@戴晓溪

我和CODE

告诉你们个小秘密, 我来豆瓣其实也是和CODE有很大的关系的… 在这里感谢@xTao和邢老师.

这一切是为什么捏?

话说那是13年下半年, 我的前公司从svn转到了gitlab. 我们在内部搭建了一个gitlab服务器. 各个产品线的代码都开始往上面迁移, 我不得不说它是市面上非常好的开源选择. 但是过了一段时间我就发现了问题:

我是python系的, 我有时候对它是不满意的, 有想法二次开发的.

这里我提一点, 很多人都说: “哎呀不要局限于编程语言, 不要去争论xx是宇宙第一语言”. 我的观点是, 只有0.1%的天才+4.9%的有天赋, 能力很强的人是可以这么说的. 剩下的95%都是在给自己学的不好找个理由和慰藉罢了. 想要走在金字塔尖就需要有执念, 否则只能沦落到打打嘴炮的地步.

我曾经尝试一边翻着《Ruby元编程》一边去读gitlab的源码, 想尝试定制它. 努力了差不多一个月放弃了. 原因无二, 这种临时报佛脚去玩转一个大公司北京, 多位大牛参与的开源项目的必然结果.

很痛苦, 但是内心又多有不甘, 于是决定做一个大事: 用python造个gitlab的轮子:

  1. 样式扒gitlab
  2. 根据gitlab的路由方式添加url
  3. 使用pygit2作为git后端

做起来才知道, 这是一个非常浩大的工程, 对于我当时的技术能力来说是个非常大的挑战. 我汲取前后端知识就基本直接用在这个项目上了.

有一天, 我产生了放弃的念头.

之前我对豆瓣也没有什么特别的感觉. 直到这天我看到清风在 C2D2 的分享

http://segmentfault.com/a/1190000000410324 http://www.infoq.com/cn/articles/douban-code-2years http://www.infoq.com/cn/presentations/tools-love-knot-of-engineer-culture

在遥远的豆瓣, 有这样一帮人和我有同样的想法. 我称他们为geek. 这是我向往的地方呀. 于是, 我决定去豆瓣

CODE开源不久, 我就到了豆瓣.

非常遗憾, 我进来的时候, CODE的核心开发大多离开了豆瓣. 我没有机会和他们一起做CODE. CODE功能也接近稳定, 心情蛮失落的我只是修了几十个bug. 加一些功能, 比如:

  1. 鼠标放在团队上也会hover一个team的card
  2. telchar - 类似quora的qlint
  3. 鼠标放在emoji会悬浮图片的放大版本
  4. 项目的guidelines

等等.

我本想拿下CODE全部的徽章, 但是给我颁徽章的人们却不在了.

CODE的未来

我会保证CODE会一直做下去. 但是单个人的能力精力有限, 我欢迎更多的公司都来用CODE, 帮助它变得更好. 也欢迎更多的同学参与进来.

未来CODE会做以下几件事情(不断补充中)

  1. 完善CODE的功能 - 现在放出来, 跑起来了. 但是预计还会有很多坑
  2. 增加初始化脚本, 填充数据
  3. 修复travis-ci
  4. 国际化 - 现在code里面有很多中文, 需要英文能力很高的同学一起来做
  5. 重构 - 有很多功能都是需要重构甚至重写的
  6. 其他方面的尝试

截图时间

前言

什么? 你已经很了解python了? 好.

我们开始做个测验. 下面有12个题目. 填个空, 让这个代码片段变的可能.

先做个例子

例子1:

>>> x, y = ???
>>> x + y == y + x
False

其中有个???. 把它替换成什么就可以让这段代码成立呢?

揭晓答案:

>>> x, y = [0], [1]
>>> x + y == y + x
False

这个还是蛮简单的. 好继续

例子2:

>>> x = ???
>>> x < x
True

答案呢?

如果使用python内置的数据结构, 确实是不可能的. 唯一可以硬造一个例子

>>> x = type("", (), {"__lt__": lambda a, b: True})()
>>> x < x
True

但是这里不需要这么复杂的去想trick出结果, 只考虑python已经实现的设计

发考卷

  1. 难度3星
>>> x, y = ???
>>> min(x, y) == min(y, x)
False
  1. 难度4星
>>> x = ???
>>> len(set(list(x))) == len(list(set(x)))
False
  1. 难度3星
>>> x, s = ???
>>> s.add(x)
>>> type(x) in map(type, s)
False
  1. 难度3星
>>> x, y = ???
>>> x < y and all(a >= b for a, b in zip(x, y))
True
  1. 难度4星
>>> x, y = ???
>>> sum(0 * x, y) == y
False
  1. 难度5星
>>> x = ???
>>> min(x) == min(*x)
False
  1. 难度3星
>>> x, y, z = ???
>>> x * (y * z) == (x * y) * z
False
  1. 难度3星
>>> x, y, z = ???
>>> x * (y * z) == (x * y) * z
False
  1. 难度4星
>>> x, y = ???
>>> y > max(x) and y in x
True
  1. 难度5星
>>> x, y = ???
>>> any(x) and not any(x + y)
True
  1. 难度3星
>>> x, y = ???
>>> x.count(y) <= len(x)
False
  1. 难度5星
>>> x = ???
>>> all(filter(None, x))
False
  1. 难度4星
>>> x, a, b, c = ???
>>> max(x) < max(x[a:b:c])
True

答案呢

这是最近我觉得蛮有趣的一个项目 pywat

上面的评星是我加上去. 也体现了我做这些题目花费的精力和时间:

3星: 很快就想到, 实验出来了 4星: 花了蛮长时间, 终于找到答案了 5星: 最后实在找不倒答案, 看了答案恍然大悟啊啊啊啊

你能做到什么程度呢?

请慎重点击: 答案地址

前言

对我来说, 以前每次面试是我审视自己, 检验自己的一种方式. 每次准备面试, 以及被面试官问住的时候才会发现, 其实我python我学的还不够好; 工作中也是, 可以从其他的同事那里获得成长. 但是我今天说的是, 我也在自己总结和思考最佳实践这件事.

我想很多人都会有意识的去读一些PEP(Python Enhancement Proposals). 了解语言设计者当时的考虑, 这些文案也是经过很长时间的讨论最后才实施的. 既然想用好这门语言, 必然需要理解设计之美. 比如我听说gvanrossum使用emacs作为编辑器, 我也使用emacs, 就是希望我可以更贴近一些python

本文根据 The Best of the Best Practices (BOBP) Guide for PythonKhan’s style-guides中对于开发中一些事物的理解和看法, 有出至PEP, 也有一些python界知名开发者, 我加入了一些我自己的理解和看法.

价值观

“Build tools for others that you want to be built for you.” - Kenneth Reitz (requests等知名库作者)

你自己都不想用的东西做出来有什么意义呢?

“Simplicity is alway better than functionality.” - Pieter Hintjens (ZeroMQ)

我对函数式编程的看法一直是看场景, 甚至于我经常会对比性能, 义无反顾的使用性能最好的, 但是代码又不难懂和繁琐的

“Fit the 90% use-case. Ignore the nay sayers.” - Kenneth Reitz

程序员都有完美主义情怀, 但是其实往往我们是在偏激的看事情 - 用户其实不case

“Beautiful is better than ugly.” - PEP 20

开发参考

“Explicit is better than implicit” - PEP 20

不要留坑, 我经常看到一些复杂的代码, 这些代码的作者写的时候明显知道自己在做什么, 但是别人很难维护和看懂. 所以我对自己的职业的基本要求就是: 那天我离职了, 后来接手的人不会经常骂我

“Readability counts.” - PEP 20

“Anybody can fix anything.” - Khan’s style-guides

我现在更多不是代码炫技, 我经常思考的怎么让最少的代码, 最简单的设计结构满足当前需求, 也能给未来一段时间里也有扩展性

Fix each broken window (bad design, wrong decision, or poor code) as soon as it is discovered.

我们改bug有个原则 - 测试要覆盖到出bug的地方. 每个人内心都有很高的代码质量的要求

“Now is better than never.” - PEP 20

明日复明日, 明日何其多. 我们在代码review的时候, 问题需要在提出的时候就去改, 永远不会说下一次再说, 因为下一次大多时候是没有下一次了

Test ruthlessly. Write docs for new features.

Even more important that Test-Driven Development–Human-Driven Development

一些细节

PEP8

很多人是排斥的, 假如你想让未来部门有自己的风格, 习惯. 让新人马上上手接受, PEP8是一个非常明智的选择

文件开头

新的文件的开头需要加一些docstring. 描述文件的作用, 编辑者, 修改原因和日期等帮助阅读者的描述.

不要添加#!/usr/bin/python(除非这个文件未来是一个可执行的文件), copyright, __author__或者其他内容.

第一行建议添加# coding-utf-8

命名

  1. Variables, functions, methods, packages, modules

    lower_case_with_underscores

  2. Classes and Exceptions

    CapWords

  3. Protected methods and internal functions

    _single_leading_underscore(self, …)

  4. Private methods

    __double_leading_underscore(self, …)

  5. Constants

    ALL_CAPS_WITH_UNDERSCORES

  6. Avoid one-letter variables (esp. l, O, I).

    永远不要使用没有意义的单字符作为变量名

PS: 这点可以折中, 假如一个代码块代码逻辑很清晰, 而 这个短的便令也只是过程中的一个间接变量之类的情况下是可以接受的

Good or Bad

列举一些正确和错误的用法.

Avoid redundant labeling.

# Good
import audio

core = audio.Core()
controller = audio.Controller()

# Bad
import audio

core = audio.AudioCore()
controller = audio.AudioController()

不要使用重复意义的标签

Prefer “reverse notation”.

# Good
elements = ...
elements_active = ...
elements_defunct = ...

# Bad
elements = ...
active_elements = ...
defunct_elements ...

Avoid getter and setter methods.

# Good
person.age = 42

# Bad
person.set_age(42)

Indentation

永远不要Tab和空格混用. 使用4个空格作为python缩进

Imports

Import entire modules instead of individual symbols within a module.

PS: 这个时候可以参考tornado的代码用法.

比如现在有这样一个包

$ tree
└── canteen
    ├── __init__.py
    ├── sessions.py
# Good
import canteen
import canteen.sessions
from canteen import sessions

# Bad
from canteen import get_user  # Symbol from canteen/__init__.py
from canteen.sessions import get_session  # Symbol from canteen/sessions.py

PS: 除非这个第三方模块的文档显式的要求这些写

Splitting tricky lines

# Bad:
badge_name = badges.topic_exercise_badges.TopicExerciseBadge.name_for_topic_key_name(self.key().name())
# Good:
badge_name = (badges.topic_exercise_badges.TopicExerciseBadge
              .name_for_topic_key_name(self.key().name()))

# Bad:
self.redirect("/class_profile?selected_graph_type=%s&coach_email=%s&graph_query_params=%s" %
    (self.GRAPH_TYPE, urllib.quote(coach.email), urllib.quote(urllib.quote(self.request.query_string))))
# Good:
self.redirect(
    "/class_profile?selected_graph_type=%s&coach_email=%s"
    "&graph_query_params=%s" % (
        self.GRAPH_TYPE,
        urllib.quote(coach.email),
        urllib.quote(urllib.quote(self.request.query_string))))

我添加的规则

from … import …

# Bad
from aa import alonglonglonglonglong, alonglonglonglonglonglonglonglonglong, \
               alonglonglonglonglonglong

# Good
from aa import (alonglonglonglonglong, alonglonglonglonglonglonglonglonglong,
                alonglonglonglonglonglong)
from aa import (alonglonglonglonglong, alonglonglonglonglonglonglonglonglong,
    alonglonglonglonglonglong, alonglonglonglonglonglonglong,
    alonglonglonglonglonglong2)  # Good。 当引入的函数/类/变量很多时, 也可以选择空 4 个空格的方式, 而不需要和首行的左括号后对齐

相对引用(relative import) 和 绝对引用(absolute import)

$cat xx/models/user/consts.py  # 如果想引用这个变量
TMP = 1

$cat xx/views/user.py
from xx.models.user.consts import TMP  # recommended。

# 假如模块层级>=3。 比如 xx/models/user/consts.py 就在根目录下的第 3 级。 如果其他当前目录下源文件需要调用它的内容。 也可以选择相对引用
$cat xx/models/user/main.py  # 需要和 consts.py 在一个目录下才可以
from consts import TMP  # Bad
from .consts import TMP  # Good

# 而且只能在包内相对引用。 包外都需要绝对引用

前言

昨天翻到了一本在github开源的书: Intermediate Python. 就有了此文, 梳理了一下一些之前翻到的对python语言细节点的答案, 博文等.

英文的

super

Python’s super() considered super!

rhettinger是python核心开发者. 这篇博文也是讲super最好最深入的博文了.

装饰器

Understanding Python Decorators

如果你还没有经常性的用装饰器, 你就要思考你的工作需求是不是的太简单了, 或者该考虑下这种AOP模式的开发的作用了

元类

What is a metaclass in Python? Metaclasses Demystified

元类是python高阶语法. 合理的使用可以减少大量重复性的代码.

防御性编程中的LBYL和EAFP

Try/catch or validation for speed?

这其实就是事先检查和异常处理2个方式的讨论

__new__ 和 __init__

Python (and Python C API): new versus init

这也是一个常见的面试题.

self

Python “self” keyword

但是注意标题. 其实self不是一个关键词. 这里知识帮助你理解self的用意

协程和并发

A Curious Course on Coroutines and Concurrency

生成器

Generator Tricks for Systems Programmers

python开发必读

Code Like a Pythonista: Idiomatic Python

unicode必读

Unicode In Python, Completely Demystified

之前我曾经非常困惑于各种unicode报错

exec和eval

Be careful with exec and eval in Python

我的观点是从来都不要用exec/eval

python性能贴士

PerformanceTips Python Performance Tips, Part 1 Python Performance Tips, Part 2

描述符

How-To Guide for Descriptors

python隐藏特性

Hidden features of Python

设计模式

python-patterns

初级python进阶文档

Intermediate and Advanced Software Carpentry in Python

这个文档不是非常难, 甚至有点过时. 但是涵盖了python的方方面面. 非常有助于开拓视野, 更了解python

中(译)文

如何理解Python关键字yield

What does the yield keyword do in Python 如何理解Python关键字yield

yield 是python语言里面让初学者困惑的关键词之一. 可以参考这2个理解让你对yield入门. 并且之后在正确的场景下使用

迭代器(Iterator)与生成器(Generator)的区别

Difference between Python’s Generators and Iterators 迭代器(Iterator)与生成器(Generator)的区别

这个是很常见的面试问题.

设计模式入门

写给Python初学者的设计模式入门

所谓设计模式其实就是经过总结、优化的,对我们经常会碰到的一些编程问题的可重用解决方案. 其实有时候会发现沃恩日常工作中的一些思考就是设计模式

python设计模式- 我写的. 供参考.

描述符

Descriptor HowTo Guide Python描述器引导(翻译)

descriptor是python高阶的特性, 可以了解下python设计的优雅. PS: 里面也提到了类方法和静态方法的区别

使用断言(assert)的正确场景

Python 使用断言的最佳时机 Best practice for Python Assert

Python track: python idioms Python的惯例

提高编码效率

Improving Your Python Productivity 提高你的Python编码效率

Stackoverflow上的Python问题精选

Stackoverflow上的Python问题精选

Python魔法方法指南

Python魔法方法指南

Python高级编程 - 我写的

Python高级编程

洪强宁的ppt.

Python高级编程(二)

PS: 这个 和上一个没有任何次序关系

前言

今天在微博上被私信, 聊了好久的关于python面试的事情. 其实感觉蛮经常的和很多人在聊这个话题. 尤其是建了一个python学习交流群之后, 群里讨论的, 私聊我的, 问的比较多的真的有python面试相关的. 总结起来大概以下几种:

  1. python面试最常用的面试题有哪些?
  2. 某个面试题感觉回答的不好, 问怎么回答比较好.
  3. 有什么面试经验可以分享.
  4. 豆瓣面试一般问什么 - 我是不可能泄题的, 以后不要这么可爱了……

突然觉得有必要专门聊聊python面试这件事儿. 随便分享下我的故事.

工作了几年, 必然面过几家. 我不是面霸, 但是也肯定有感觉特别奇葩的, 没对上眼的, 完虐我的,励志的, 让我感动的. 让我感恩的.

来个趣事儿

国内python圈有名的公司不多. 12年的时候觉得要从运维开发转型为真正的开发, 面试了某知名公司S. 一直到现在我还觉得他的面试模式很好 - 初步筛选之后会发面试题, 2个题目任选其一, 一周做好. 当时python刚学会一年多, 反正蛮辛苦的还是做完了. 后来接到一面的电话. 当时觉得他们的工作环境特别好, 想着能留下来该多好. 这个组的面试风格比较特别 - 三个组员一起来面试, 轮流问问题, 有技术的, 有个人兴趣的, 有职业规划的. 为什么说这个呢? 这是我工作以来影响最深的面试, 甚至说对我未来影响很大, 一直到现在我都非常感谢他们. 现在我每次面试其他人, 都要花的时间比较多, 希望挖掘更多的候选人的优点, 给更多的建议和帮助. 总是想起他们对我的建议. 我们说了什么呢?

我清楚的记得几个事情

  1. 看我简历学了熟悉django. 问我django请求到响应的流程. 没有回答上来. 其中一个面试官给我解释下流程.
  2. 问了一些python语法, 应用场景, 但是我大都没有深入了解, 事后我挨个查了这些知识点, 发现其实我只是学会了皮毛
  3. 无意间聊到了编辑器, 我说用vim, 但是只是会用:q, :%s这有限的几个. 他们说这么久了, 就没有想想应该花时间好好的学习下, 提高工作效率么? 很难想象我是怎么开发的.. 说了很多, 我都有点完全被鄙视的想快点结束这个面试了.

面试其实时间还挺长的. 最后我问了我每次面试结束都会问的问题: 你们对我有什么建议?

他们说了这么几点, 和大家共勉

  1. 他们觉得我买了好多书, 想看想学的很多, 但是都没有深入. 建议我砍掉一半的兴趣, 把这些时间专注于做其中的几件
  2. 一个领域学习1,2个就好了. 比如web框架. 只要学好django或者flask, 理解原理. 用什么框架已经不重要了
  3. 好好学习一个编辑器. 驾驭好它, 让它提高你的工作效率.
  4. python学的不够深入, 建议我在细节上一个一个的抠, 力争弄清楚每一个, 积少成多

说到这里, 好像没啥有趣的.. 对吧

14年初, 在我面试豆瓣前, 我特意给S当时虐我的三人之一发邮件. 希望获得一个面试机会. 大概因为之前特意吐槽了S开源的一个项目还对我有兴趣, 很快又拿到了面试题. 这次的要难很多, 我还拖了一天交卷. 但是还是获得了一面的机会. 然后一直到最后谈薪资.

不同的是, 当时三人已经只剩下一个. 面试过程也没再问python问题(面试题答案应该已经证明了).

当时我已经准备好虐他们了….

  1. 我真的不再关注那么多的领域, 当时买的好多书甚至因为搬家给卖掉了却出来没看过
  2. 我曾经专注的看过python标准库和一些项目的代码, 给很多开源项目贡献代码, 甚至给python标准库贡献了代码
  3. 我都不用vim, 改用emacs了
  4. 后来面试豆瓣时候也基本没有问python问题, 可见我python能力还好 (*^ー^)

还没完….

以前一面某S的一个工程师. 聊着聊着.

他说: 你知不知道有个叫做XXX的? 我说: 我就是. 他说: 啊! 我还在想我会不会遇到你呢? 我说: 嘿嘿, 你如愿了 他说: 之前听别人说过你. balabala

机会是给有准备的人的. 不是python工作不好找, 只是没学好. 当时去S面试是个下午, 那天阳光和煦, 阳光照在我们那个屋子里面的玻璃桌上面, 面试的气氛很轻松. 当时觉得他们每个人对自己做的事情,对python都非常了解, 你是不是也想去这样的环境呢? 那么努力吧..

我来豆瓣也是一个励志的故事, 但是有点脱题了, 我们开始说python面试吧

我推崇的面试方式

这个更适合面试官来看

  1. 上面提到的, 决定要不要一面, 先发面试题来做, 看题目功能实现, 代码风格, 注释等和团队文化匹配度决定要不要一面, 更少的减少无用面试时间
  2. 知道创宇有一道爬虫的面试题写在博客里面, 想去的人把题做完发给他们就好了. 这道题确实不错. python掌握不好的确实做的会比较吃力, 也会直接暴露细节点掌握情况, 也可能会留下惊喜. 这样模式的题目也是一个筛选合适人才的办法

候选人应该做好哪些技术准备呢?

网上可以搜到一些面试题, 找了一些还不错的链接列出来

http://programmers.stackexchange.com/questions/21917/python-interview-questions
https://github.com/sigmavirus24/python-interview-questions
https://gist.github.com/xiangzhuyuan/7454001522d275021b2d
https://github.com/ContinuumIO/interview-questions
https://github.com/Flowerowl/python_articles
http://marselester.com/preparation-to-python-interview.html
https://github.com/zachwill/cracking-the-coding-interview
http://www.bogotobogo.com/python/python_interview_questions.php
https://www.quora.com/What-are-good-Python-interview-questions
https://www.reddit.com/r/Python/comments/1knw7z/python_interview_questions
https://github.com/1st/interview/blob/master/python.md

还有2个中文:

https://github.com/taizilongxu/interview_python
https://gist.github.com/prim/3e7f814187c715541ef2

毕竟我也是面试官, 就不划定那些是常见问题了. 防止我的主观意见对于未来影响面试者的评价公正性. 而且我也要说一点, 我也不评论上述文章中的答案的正确性了. 大家还是需要在面试前先做些查询和研究了

用心

  1. 去某公司面试前, 或者立志要去该公司. 最好先了解公司用到的python相关的技术栈, 这样可以有针对的准备相关内容
  2. 针对性的准备想要做的职位的python技能需求. 比如面试运维开发, 多准备系统, 数据库, 配置管理相关的知识, 比如web框架(除非了解到该职位需要)
  3. 及时关注python技能最新用法, 或者推荐用法. 多了解python3的趋势, 有可能会被面试官问到.
  4. 有个github账号. 能把自己的想法实践出来的python项目, 这样就多了了解你的机会. 可能在面试中就会少问你对应的技术点