如果你报名了今年的 COSCUP 2019(开源人年会),欢迎来听我的演讲《如何在两年内从初学者成长为流行开源项目维护者和技术书作者?》,8 月 17 号(第一天)下午 2 点 55 开始,在 IB202 会议室。
如果你对这个演讲感兴趣,但是没法参加,那也没关系,会后我会把演讲视频和幻灯片分享出来。
庆幸能在两岸关系进一步恶化之前,去台湾玩一趟,希望一切顺利。
如果你报名了今年的 COSCUP 2019(开源人年会),欢迎来听我的演讲《如何在两年内从初学者成长为流行开源项目维护者和技术书作者?》,8 月 17 号(第一天)下午 2 点 55 开始,在 IB202 会议室。
如果你对这个演讲感兴趣,但是没法参加,那也没关系,会后我会把演讲视频和幻灯片分享出来。
庆幸能在两岸关系进一步恶化之前,去台湾玩一趟,希望一切顺利。
有很多初学者因为受各种文章的吹捧而痴迷「前后端分离」这个词,刚开始学后端 Web 框架就想知道怎么实现前后端分离。就我目前有限的经验来看,前后端分离并没有那么重要,只是另一种程序架构(开发模式)而已。和传统的后端渲染的 Web 程序相比,并没有明显的优劣之分,两种方式都各有优缺点,也各有适合的场景。
没必要过分追捧任何一种语言、框架、工具、操作系统……都了解都能用最好,工具永远没有要做的事情重要。没有能胜任所有工作的完美工具,更多时候是按需选用最合适的工具。
虽然一样都是没有时间玩,但购买实体游戏光盘和卡带要比数字版更让人感到幸福,至少你每天都可以看到一排花花绿绿的游戏放在那里,没事还可以拿过来换一换排列顺序……换句话说,实体游戏会让你有一种踏实的拥有游戏的感觉。等你有了一橱柜的游戏,还可以用来炫富(仅对游戏玩家有效)。
把自己的目标公之于众,有可能会因为受到监督而更容易完成目标,也有可能会让你潜意识里感觉自己好像已经完成了目标,从而让计划更难执行。我更相信前一种理论,所以决定现在公布第二本 Flask 书的写作计划。
尽管我很想早一点深入学习更多的东西,而不是局限在 Flask(或 Python) 领域,但事实是,在这一个领域就已经有太多的东西需要研究和学习……目前来说,我最想解决的就是 Web API 的编写问题。《Flask Web 开发实战》虽然在第十章介绍了 Web API 的大部分基础概念,但是只实现了一种 OAuth 认证流程,也没能深入更多内容,包括数据校验、请求封装等。因此,我决定再写一本书来覆盖这个主题。
另一个原因是,我在上一本书的电商页面、豆瓣条目还有其他地方收集到了一些批评,其中有一些很中肯,所以我想写一本更好的 Flask 书。除了克服这些批评里提到的缺点,我也会尝试更科学的写作方式,不会像上一本书那样在早期印刷版本包含那么多的笔误和疏漏。
作为试水,我在 PyCon China 2019 上海场会有一个相关主题的演讲:《基于 Flask 的 Web API 开发指南》,如果你感兴趣的话,可以考虑报名参加。
不同于《Flask Web 开发实战》所追求的大而全,这本书的定位是一个小而精的 Flask 书。它会包含下面这几部分:
这本书一来可以衔接《Flask 入门教程》,二来可以补充《Flask Web 开发实战》没有覆盖的内容。当然,对于学习 Flask,囊括几乎所有相关主题的《Flask Web 开发实战》仍然是一个不错的选择。
对于相同的主题,我会考虑使用不同的工具,比如《Flask Web 开发实战》里单元测试使用 unitttest,那么这本书就会介绍用 pytest;上一本书里编辑器介绍使用 PyCharm,这一本书或许就会介绍使用 VSCode。
下面是这本书的其他具体设计:
作为后续,在这本书完成后,我计划写一本电子书来介绍如何使用 Vue.js 基于这本 Flask 书编写的 Web API 来开发客户端。尽管我现在还没入门 Vue.js……但是我已经把放相关内容的网站域名准备好了:HelloVuejs.com(它和 HelloFlask.com 是兄弟域名 :p)
预计的发售时间是明年愚人节,即 2020 年 4 月 1 日。因为 Flask 的诞生时间是 2010 年的愚人节,所以明年愚人节会是 Flask 诞生十周年纪念日,一个很完美的发售时间。
如果你对这本书感兴趣,可以关注我的微信公众号、Twitter 和豆瓣账号获取最新动态,或是访问这本书的主页。
2020/4/1 更新:Flask 新书完成时间推迟
在公开上一本写作消息的文章里,我征集到了大约 40 条建议,虽然没能完全采纳,但我都一一考虑过这些很有价值的建议。对于这本新书,在内容、形式或是其他任何方面,你有什么意见和建议?欢迎发评论分享你的想法,谢谢。
在 Python 诞生 30 周年之际,PyCon China 2019 将于 9 月 21 日在上海(主会场)举行,今年我们设置了闪电演讲和 Flask 专场,正在征集相关议题。
如果你对演讲不感兴趣,但是想购票参加,可以直接跳到文章结尾。
5 分钟能做的事情很多,但是你有没有想过用这 5 分钟在技术大会上进行一场闪电演讲?如果你有些心动的话,现在就一个这样的机会放在你面前!
尽管只有 5 分钟,你仍然需要做足准备。反过来,5 分钟并不短,足够让你完成一场让人记忆深刻的精彩演讲。
不用担心自己「资历」不够,因为我们只关心你的演讲内容是否有趣和有质量;也不用担心自己没有演讲经验,因为我们将在会前进行一系列线上培训和交流,帮助你完成几次试讲并给出相应的建议和指导。
无论你最终是否提交议题,只要你感兴趣,都可以加我的微信(备注「闪电演讲」),我会邀请你加入微信交流群。
除了策划闪电演讲,我还负责策划一个 Flask 专场。如果你在 Flask 方面有过丰富的探索和实践,想和大家分享你的知识和经验,欢迎报名。当然,如果你想分享的内容和 Flask 无关,但和 Python 有关,也欢迎报名。
总而言之,只要你的演讲和 Python 有关,并且内容不算无聊,那就大胆提交你的议题吧!
点击下面的链接即可提交议题申请:
报名的城市会场不限上海,报名将在 8 月 10 号截止,如果你申请的是闪电演讲,记得在「演讲类型」选项里勾选对应选项。
如果你的议题成功入选,除了可以在 PyCon China 2019 大会上分享你的想法外,你还可以获得下面的福利:
如果你对演讲不感兴趣,那么报名参加大会也是一个不错的选择,点击下面的链接购买上海场门票(早鸟票 7 月 30 号截止):
https://www.bagevent.com/event/5293611
在这里,你将有机会交到穿着同款格子衬衫而且使用 Python 的朋友,还有机会和很多 Python 技术大牛小牛们面对面交流。我邀请到了两位 Flask 领域的重量级嘉宾,一个是 Flask 的作者 Armin Ronacher,另一个是 Flask 的维护者之一 Hsiaoming Yang(lepture)。Flask 目前的核心维护者 David Lord 虽然没能成行,但是表示可以远程支持 Sprint 活动。
如果你离上海太远,也可以考虑参与其他会场,比如北京、杭州、成都、深圳等等,具体议程可以关注 PyChina 公众号或 PyCon China 官网。
PyCon China 2019,期待你的参与!
Splatoon(喷射战士)太好玩了!BGM、画面、动作、玩法都很有趣,体感控制慢慢也已经习惯。如果早一点遇到,估计不会想玩 CS 之类的游戏(太难了 ><)。难度算得上可控,在对面没有狙的情况下,不会很容易死掉,没玩过射击游戏的女生和小朋友也很容易上手(据说日本每个礼拜会有几万小学生加入战斗 XD)。也不会有很强的挫败感,毕竟你涂了地嘛。
随着玩的次数多了,经常会遇到「跳舞局」,也就是大家既不涂地也不互不攻击,一起在地图上的某个地方跳舞、蹦迪或是集体跳水自杀,总之就是各种行为艺术。一般会在一开局就有人用高频率的潜墨起身的动作(这个动作如果在杀死敌人后做就是嘲笑、得意的意思,没视频比较难形容)来发出信号,意思就是「我们这一局跳舞吧,不要杀人了」。
还会有人在地上写字画画:

非要说缺点的话,大概有两点。第一是网络,偶尔会掉线,而且工作日匹配会慢一点(也许是因为玩家都跑到 Switch 上玩 2 代了)。另外一点就是社交功能基本没有,既没有语音也没有快捷短语,大家匹配到一起玩一局,不管赢得多么精彩,过程有多么曲折刺激,战斗结束就只能默默的相忘于江湖……
最多杀敌是 23(滚筒,推塔模式),用射程超长的那款狙击枪做到过一次 12 杀 0 死:

下面是手动录制的一次最佳开局(因为环境音太吵,所以去掉了声音,备用链接):
Jinja2 有三种定界符语法:
{{ ... }} 用来标记变量;{% ... %} 用来标记语句;{# ... #} 用来标记注释;如果你同时使用了 JavaScript 模板引擎,而该 JavaScript 模板引擎也使用相同的语法标记符,那就会产生冲突。一般来说,有下面三种兼容性处理方式:
第一种方式最直观,使用 Jinja2 的 raw 标签声明原生代码块,也就是不需要进行后端渲染的代码块。使用 raw 和 endraw 标签把 JavaScript 模板部分标记出来即可,比如:
{% raw %}
<div id="app">
{{ js_var }}
</div>
{% endraw %}
这种方式的副作用最少,尽管需要多几行代码,但不会影响你写 Jinja2 或其他 JavaScript 库的语法习惯。
第二种方式是修改 Jinja2 的语法定界符号,一般只修改变量定界符即可,其他的按需修改。具体通过修改程序实例的下面几个属性来实现:
from flask import Flask
app = Flask(__name__)
app.jinja_env.block_start_string = '(%' # 修改块开始符号
app.jinja_env.block_end_string = '%)' # 修改块结束符号
app.jinja_env.variable_start_string = '((' # 修改变量开始符号
app.jinja_env.variable_end_string = '))' # 修改变量结束符号
app.jinja_env.comment_start_string = '(#' # 修改注释开始符号
app.jinja_env.comment_end_string = '#)' # 修改注释结束符号
第三种方式是修改 JavaScript 模板的语法定界符号,具体方法因 JavaScript 模板/框架而异,可以参见相关文档了解。以 Vuejs 为例,下面将模板定界符改为中括号:
var app = new Vue({
el: "#app",
delimiters: ["[[", "]]"],
data: {
message: "Hello Vue!"
}
})
如果你觉得使用 raw 标签太麻烦,而修改语法定界符又不习惯,这里还有一个折中方法:两边都使用双花括号作为定界符,但根据花括号内部是否添加空格来进行区分。
具体来说,对 Jinja2 变量使用 Jinja2 标准语法,也就是使用 {{ 作为变量开始符号,注意花括号右侧有一个空格,结束符号类似,需要在花括号左侧加入一个空格,即 }}。实际示例如下:
{{ jinja_var }}
而 JavaScript 模板使用没有空格的双花括号,即:
{{js_var}}
这是一种更适合心细的懒人的方法,如果是团队项目,可能会对不习惯这种用法的人造成困扰,记得在文档里注明。这种方式只需要修改 Jinja2 定界符:
app.jinja_env.variable_start_string = '{{ '
app.jinja_env.variable_end_string = ' }}'
另外需要注意的是,如果你使用了其他 Flask 扩展的内置 Jinja2 模板或宏,需要确保它们都使用了包含空格的标准 Jinja2 语法。举例来说,用来方便集成 Bootstrap 的 Flask-Bootstrap 就没法使用,需要使用替代的 Bootstrap-Flask。其他扩展,比如 Flask-Admin,Flask-Security 暂未测试,欢迎了解的同学反馈兼容情况。
经常听到有人说「做自己」,比如有人做什么事情失败了,别人就会安慰他「没关系,做自己就好了」;自己经历挫折和打击,就自我安慰「做自己吧,不用理会别人的批评」。这完全是扯蛋,糟糕就是糟糕,失败就是失败,自己很差劲也要坚持做自己吗?这分明就是在为自己找借口,是和「我没有天赋」一样的俗套借口。
类似的话还有「跟随你的内心」、「走自己的路,让别人说去吧」,先不管说这些话的人原意是什么,但它们绝不是让你坚持错误的观念、决策和生活习惯的理由。没有礼貌,不尊重别人跟「做自己」没有任何关系,更不是「特立独行」。这些话对于心智成熟的成年人来说才有积极意义,如果你不打算研究这些话的本意,那就不要滥用。
对南京的印象,除了李志的几首歌,剩下的大概就只有梧桐树了。高中时在豆瓣上看到某篇日记写南京的梧桐树,惊艳于梧桐树的美,也为被砍掉的梧桐树惋惜。在中国,尤其是近代,大部分旧的、美的东西,不是被抢夺,就是被破坏。
折腾了一星期,总算安顿下来。说起来这是第二次来南京了,上一次是作为一个游客,匆匆停留,而这次至少要在这里住一年时间,希望可以更深入地了解这个城市。
今天又对博客进行了一次大翻修:去掉了个人主页的特殊样式,丰富了个人主页的内容;博客标题从「李辉的书桌」改成了「李辉」,所以现在的这个网站的定位从「博客」变成了「个人网站」;添加了英文博客,主要的目的是练习英文写作,要是能找到外国人帮我修改语法错误就好了。
无论是程序员,还是其他需要长时间使用电脑的工作者,都会面临很多健康问题,除了简单直接的猝死,更常见的是各种重复性劳损(Repetitive Strain Injury,RSI),比如颈椎病、腰背疼痛、干眼症、鼠标手等。除了保持正确坐姿、使用各种效果不一的人体工程学装备外,最重要的是避免长时间工作,每隔一段时间站起来休息和放松。
听起来很简单,但对大部分人来说,靠自觉定期休息基本不可能,所以我们需要借助外力来强迫自己休息。
让你的电脑每隔一段时间自动锁定会是一个好办法。这篇文章会介绍两个这样的工具,当你使用电脑一段时间后,它会自动显示一个休息提示,屏蔽你的任何输入,直到休息时间结束:
Workrave 是 2002 年发布的开源 RSI-prevention 程序,它是目前的最佳选择:
Workrave 的功能很全面,不仅包含基本的休息提醒,还可以监测活动状态,并且内置了体操动作提示(别担心,不是你想象的那种体操,只是一些拉伸动作)。除此之外,你还可以在统计选项里查看你每天的活动情况,包括休息次数、鼠标和键盘使用情况。
唯一的缺点是,它不支持 macOS 系统。如果你使用 macOS 系统,在支持 macOS 的替代品里,功能稍微简单一些的 Stretchly 是个不错的选择:
这两个程序都是开源项目,在对应 GitHub 项目的 releases 页面可以下载到最新版本。
你可以将界面语言设为中文,然后尝试按照自己的工作习惯调整设置。对于核心功能的休息设置来说,这两个程序都把休息分为两类,短休息和长休息。建议把短休息设为 20~25 分钟一次,每次 2 分钟;长休息 50~60 分钟一次,每次 10~15 分钟。另外,Workrave 还支持设置每天使用电脑的总时长限制,可以根据需要进行设置。
不要把休息频率设置的太高,因为你的电脑上可能被安装了监视「空位」时间和离开电脑次数的软件……
为了让强制效果更强一点,建议在 Workrave 的首选项里为每个休息类别都设置不在休息前显示提示,也不要显示推迟和跳过按钮;Stretchly 类似,可以勾选「阻止跳过」,并取消勾选「允许推迟」。
当然,即使这样设置,太沉迷于手头工作的时候你还是可以找到某些特殊方法跳过休息。但是,为了让工具真正发挥作用,你要有一点点遵守规则的自觉。
从今天开始,正视健康在生活中的优先级吧。祝你有个好身体!
本文首发于公众号「李辉的代码厨房」。
本文隶属于《Flask Web 开发实战》番外系列。这篇文章会介绍如何在 Flask 项目中集成 Celery。
第一步是创建一个 Celery 程序实例。因为 Flask 程序实例通常会命名为 app,为了避免冲突,我们一般会把 Celery 实例命名为 celery 或 celery_app:
from celery import Celery
celery = Celery(__name__, broker='pyamqp://guest@localhost//')
@celery.task
def add(x, y):
return x + y
大多数教程,包括目前的 Flask 文档里都会介绍用下面的方式加载配置:
celery.conf.update(app.config) # 这里的 app 是 Flask 程序实例
也就是把 Celery 配置和 Flask 配置写在一起,然后从 Flask 程序实例的配置字典里更新配置。
但问题是,Celery 从 4.0 开始启用新的小写配置名,某些配置被新的名称替换。虽然旧的大写配置仍然支持,但如果你打算使用小写配置名,或是打算在未来进行迁移,这里的配置加载方式就会失效,因为 Flask 在从文件或对象导入配置时只会导入大写形式的配置变量。
因此,我建议将 Celery 配置写在单独的文件里,不要和 Flask 配置混在一起。按照 Celery 文档的示例,你可以在当前目录创建一个 celeryconfig.py 文件(或是其他名字)保存配置:
broker_url = 'pyamqp://'
result_backend = 'rpc://'
task_serializer = 'json'
result_serializer = 'json'
accept_content = ['json']
timezone = 'Europe/Oslo'
enable_utc = True
然后使用下面的方法加载配置(使用其他模块名,或是在其他路径时,记得修改传入的字符串):
celery.config_from_object('celeryconfig')
如果需要在创建 Celery 实例时传入 broker 和 backend 配置,可以直接写出或是从配置模块中导入:
from celeryconfig import broker_url
celery = Celery(__name__, broker=broker_url)
你可以单独创建 Celery 程序,但我们通常会需要为它添加 Flask 程序上下文支持,因为有时候你的 Celery 任务函数会用到依赖于 Flask 程序上下文的某些变量。
下面我们为 Celery 创建了一个工厂函数,在工厂函数中创建 Celery 实例,加载配置,并实现 Flask 程序上下文支持:
from flask import Flask
from celery import Celery
from celeryconfig import broker_url
def make_celery(app):
celery = Celery(__name__, broker=broker_url)
celery.config_from_object('celeryconfig')
class ContextTask(celery.Task):
def __call__(self, *args, **kwargs):
with app.app_context():
return self.run(*args, **kwargs)
celery.Task = ContextTask
return celery
app = Flask(__name__)
celery = make_celery(app)
在定义 Celery 任务的模块里,比如 tasks.py,你可以导入这个 Celery 程序实例:
from app import celery
@celery.task
def add(x, y):
return x + y
当 Flask 程序也使用工厂函数创建时,我们可以全局创建 Celery 程序实例,然后在创建 Flask 程序实例的工厂函数里更新 Celery 程序配置并进行上下文设置:
from flask import Flask
from celery import Celery
from celeryconfig import broker_url
celery = Celery(__name__, broker=broker_url)
def create_app():
app = Flask(__name__)
register_celery(app)
return app
def register_celery(app):
celery.config_from_object('celeryconfig')
class ContextTask(celery.Task):
def __call__(self, *args, **kwargs):
with app.app_context():
return self.run(*args, **kwargs)
celery.Task = ContextTask
同样直接导入 Celery 实例并创建任务:
from app import celery
@celery.task
def add(x, y):
return x + y
这本来是一个完整的 Celery 入门教程,但因为去年的一次硬盘损坏,对应的示例程序弄丢了,暂时没有毅力重写一遍,所以这篇文章只抽取了其中和 Flask 相关的内容。
因为距离初稿写作的时间已经过去半年多,Celery 的最新版本也已经是 4.3.0,如果文中有什么疏漏,或是有更好的实现方式,欢迎评论指出。