标签归档:编程

代码厨房欢迎你

代码厨房是一个面向编程和开源爱好者的社区。社区的主体是坐落在 codekitchen.community 的论坛。这个论坛的前身是创建于 2019 年 1 月 11 日的 HelloFlask 论坛(HelloFlask discuss!),因为论坛服务器一直在海外颠沛流离,所以访问起来并不是很顺利。最近把论坛以及 628 位 HelloFlask 原住民一起搬家到了香港,改头换面变成代码厨房社区。

「代码厨房」最早是我创建的公众号的名字。同一时间注册了 daimachufang.com,想要在这个网站上放些什么已经不得而知。后来公众号一再改名,代码厨房已经不见。再一次想起来是在去年 10 月, 29 日心血来潮去参加中国开源年会的开源集市。作为现场唯一一个个人展位,我带去了两个项目。一个是方学园,另一个便是代码厨房俱乐部

出发前一天为代码厨房俱乐部更新了 daimachufang.com,也就是下面的样子:

俱乐部现场成立,现场报名。报名单上收集了十个人,最后筛选到五个。算上我自己,六个人在一年内完成了四次聚会。大家互相带来很多新想法和思考,也玩得很开心,但逐渐有点忘记最初想要做什么。于是,在 2023 年的 10 月 22 号,最后一次聚会,大家回到了报名的地方——微软 Reactor。我在那里重新介绍了代码厨房社区的构想

代码厨房的核心构想是「一个让人快乐和放松的编程社区」,主要的板块是:

blank

不论你是当下、曾经还是未来的编程爱好者,都可以加入我们。代码厨房欢迎你!

组织「编程一小时」活动失败记

编程一小时(Hour of Code)」是由非盈利组织 Code.org 发起的公益活动,会在每年十二月初举办(计算机科学教育周)。简单来说,类似「地球一小时」活动,「编程一小时」活动就是在中小学引导学生们学习编程一小时。使用的材料大都是一些图形化的编程游戏(比如《我的世界》编程一小时教程),在游戏里使用类似 Scratch 的拖拽式编程逻辑块来操纵游戏中的人物做各种事情。

中国的「编程一小时」活动主要由微软和苹果这些大公司发起和主办。月初的时候,微软 MVP 项目组开始召集 MVP 做活动的讲师。南京有好几个学校需要讲师,但是我已经不在南京了,所以就想着在当地(徐州某县级市某镇某村)的中小学组织一次。在网上找了一些往年的活动记录,发现也有在农村组织的,想着应该没什么问题。

先是给高中的老师发了消息,没回;然后去村里的小学找校长,爬了三层楼没找到校长室,找到校长的电话打过去,校长说电脑坏了;发消息给初中的老师,老师说他们学校没有电脑;去了乡里的小学,门卫大叔说校长刚走;趁还没放学,我又赶到邻村的小学,老师告诉我要有教育局的通知才行。

「你好,我是微软的社区专家,想在你们学校举办一场免费的编程科普公益活动,叫做编程一小时。微软会提供相关的物料,我来做讲师,你们只要提供计算机教室和组织学生就可以了。」——听起来的确有些像骗子,也许对方以为我是要来推销少儿右脑开发心算术或是人工智能 5G 学习机。按理说我应该在这里就放弃了,但是我有点不甘心。尽管已经有 3 小时 48 分钟的沉没成本,我还是打算再试一下。

第二天,我花了五十分钟车程到达教育局,但是没到五分钟就出来了——没成想连教育局的门都进不去。教育局门卫室的保安问我找谁,我说:「我是……我来……」。保安又问:「你到底要找谁?要去哪个科室?」。我说:「我想来咨询一下关于进学校做免费编程培训的许可问题」。保安说:「没有这个科室,你想去哪个学校直接去找学校谈」。我说学校让我来找教育局,保安说来教育局没用得去找学校。在来回进行了几遍类似的对话后,保安有点生气,气冲冲地说「你这个人年纪轻轻怎么听不懂话呢!」。我也有点生气,但也只能气冲冲说句「好,谢谢!」。

既然到了市里,就想着再碰碰运气,所以紧接着我又去了市里最好的初中。这所初中的北门离公交站近,所以先去了北门。门卫师傅说校长室在南门,办事都走南门。因为校园不让进,所以我只能绕墙去南门(两门相距 530 米)。到了南门后,门卫师傅说校长不在,去开会了。我说那我找年级主任也行,师傅问我找哪一个年级主任……沟通(扯皮)半天后终于让我进了门卫室,让我等等看,说校长兴许一会儿来。一阵沉默。沉默之后我多介绍了一下自己,拿出来更多的宣传材料。门卫师傅指着玻璃桌面下的某个电话,让我打到校长室试一试,没人接。又是一段沉默。接着我又详细介绍了自己要做的事情。师傅提议让我去找副校长,副校长室在北门八号楼五楼,让我去北门。于是我绕墙回到北门,北门师傅问我找哪一位副校长?打过电话没有?预约了吗?我说南门师傅让我走北门找副校长,北门师傅说办事都走南门,没有预约校园不给外人进,让我走南门。如此重复几遍,直到师傅不耐烦了,我又绕墙回到南门。和南门师傅说着说着,师傅又指了桌面下某位副校长的手机让我打,打不通。继续沉默,沉默是今晚的南京市长江大桥。过了一会儿师傅又翻出另一本电话簿,找到校长的手机让我打,依然没人接。我看了看崭新的教学楼,告别门卫师傅,再绕墙走回北门,准备坐公交车离开这冰冷的城市。不幸的是,因为太晚了,回乡下的公交车已经没了,我只好斥巨资打车回家。

第三天一早我试着加上了副校长的微信,这是我离成功最近的一次。我们聊得很顺利,直到校长告诉我他们新教学楼刚建成,学校计算机教室还没装配……擦干眼泪,我又去了乡里的小学,上次去校长刚走,这次去校长刚好在门卫室。我听到了熟悉的答案:「这个活动挺好,不过校外的培训要有教育局的批准才能做,你得去教育局申请」。至此,耗时 7 小时 54 分的「编程一小时」活动策划正式宣告失败。

本来还想着也许会让某个小朋友喜欢上编程,若干年后他在写职业生涯回忆录的时候可能还会提到我——「走上这条路是因为小时候某一天不知道从哪里来了一个人在我们学校上了一堂编程启蒙课……」。现在也好,万一他以后因为做程序员得了颈椎病和脱发,可能还要怪到我头上呢。

2021/11/24 Update:我去联系了去年约好今年合作的那位校长。校长三天后回复我说计算机教室还没有安装好,我说可以进行「不插电编程」,校长说下午再聊。

WTForms自定义验证方法(行内验证器)是如何被调用的?

这篇文章基于我在知乎上的这个回答,进行了相应的简化处理,放到这里做个备份。

万能的回答

答案在源码里。

简单的回答

WTForms会在你对表单实例调用Form.validate()方法时收集所有的行内验证方法,然后在对每个字段调用Field.validate()方法验证时将这些自定义行内验证方法一并和通过validators参数传入的验证器列表一起调用,进行验证。因为WTForms在调用时把对应的field作为参数传入了行内验证方法,所以你可以在自定义验证方法中通过field.data获取对应字段的数据。

深入的回答

WTForms会在你对表单实例调用Form.validate()方法时收集所有的行内验证方法。在Form类中的validate()方法定义中,你可以看到WTForms是如何收集这些行内验证方法的:

class Form(with_metaclass(FormMeta, BaseForm)): 
   ....
   def validate(self):
        extra = {}
        for name in self._fields:
            inline = getattr(self.__class__, 'validate_%s' % name, None)
            if inline is not None:
                extra[name] = [inline]

        return super(Form, self).validate(extra)

源码位置:github.com/wtforms/wtfo

这里迭代所有的字段属性,然后表单类中是否包含validate_字段名形式的方法。如果有,那么就添加到extra字段里,这个字段被传递到BaseForm类的validate()方法中。在BaseForm类的validate()方法中,WTForms迭代所有字段,并对每个字段调用Field.validate()方法验证字段,继续传入自定义的行内验证方法:

class BaseForm(object):
    ...
    def validate(self, extra_validators=None):
        self._errors = None
        success = True
        for name, field in iteritems(self._fields):  # 迭代字段名和字段对象
            if extra_validators is not None and name in extra_validators:  # 判断当前迭代字段是否存在自定义验证器
                extra = extra_validators[name]
            else:
                extra = tuple()
            if not field.validate(self, extra):  # 调用字段类的验证方法进行验证,传入自定义验证器
                success = False
        return success

源码位置:github.com/wtforms/wtfo

而在字段基类Field的validate()方法中,WTForms使用itertool模块提供的chain()函数把你实例化字段类时传入的验证器(self.validators)和自定义行内验证器(extra_validators)连接到一起:

class Field(object):    
    ...
    def validate(self, form, extra_validators=tuple()):
        ...
        # Run validators
        if not stop_validation:
            chain = itertools.chain(self.validators, extra_validators)  # 合并两类验证器
            stop_validation = self._run_validation_chain(form, chain)  # 运行验证器
        ...

源码位置:github.com/wtforms/wtfo

连接起来的所有验证器赋值为chain变量,并传入到self._run_validation_chain(form, chain)进行进一步调用:

class Field(object):    
    ...
    def _run_validation_chain(self, form, validators):
        for validator in validators:
            try:
                validator(form, self)  # 传入字段类本身作为第二个参数

源码位置:github.com/wtforms/wtfo

这个方法迭代所有的验证器对字段数据进行验证。关键在于validator(form, self),可以看到这里传入了第二个参数self,即Field类本身,这也是为什么你可以在自定义验证方法中通过field.data获取当前字段数据。

Python中的下划线有多少种用法和含义?

这篇文章来自我在知乎上的这个回答,做个备份。

大概有10种。

如下:

# No.1
# 在交互式解释器中获取上一个语句执行的结果
# 比如:
# >>> 1+1
# 2
# >>> _
# 2
# >>> _ * 5
# 10
_

# No.2
# 用来在函数、模块、包、变量名中分隔单词,增加可读性
var_foo_bar

# No.3
# 内部使用的变量、属性、方法、函数、类或模块(约定)
# from foo import * 不会导入以下划线开头的对象
_var

# No.4
# 避免和保留的关键字冲突(约定)
# 比如:class_、type_
var_

# No.5
# 在类内的私有变量(private)
# 类外部无法直接使用原名称访问
# 需要通过instance._ClassName__var的形式访问(name mangling)
__var

# No.6(这一条存疑)
# 在类内的保护变量
_var_

# No.7
# Python内置的“魔法”方法或属性
# 你也可以自己定义,但一般不推荐
# 比如:__init__, __file__, __main__
__var__

# No.8
# 作为内部使用的一次性变量
# 通常在循环里使用
# 比如:[_ for _ in range(10)]
# 或是用作占位,不实际使用的变量
# 比如:for _, a in [(1,2),(3,4)]: print a
_

# No.9
# i18n里作为gettext()的缩写
_()

# No.10
# 用来分隔数值以增加可读性(Python 3.6新增)
# 比如
# >>> num = 1_000_000 
# >>> num
# 1000000
1_000_000

参考链接:

关于这个博客

这要从我开始学编程说起。

当时只是想做个独立博客出来,同时又有开发一些软件的想法。所以开始学python,之所以选择python,是因为受了众多知友的影响(蛊惑),当然,更多是因为它的简单易于学习,同时也很喜欢它所蕴含的哲学思想。初衷是用它来做网站和软件,但这时博客已经用wordpress构建了,做软件它也不是最佳选择。或许我该转向java或是object-c,但我已经学了一些基础概念,又不想就这样放弃。所以还是把它作为我的入门语言,并且用它来实现一些有趣的功能。

回到正题,这个博客主要用来记录我学习编程和英语以及其他兴趣点的经验与感想,然后是我日常的一些想法。等到若干年后再来看应该是不错的回忆。之所以不选择blogger或是其他博客网站,是因为有自己的独立的域名和网站给我一种自由的感觉,不仅是审查上,更多的是完全掌控自己的空间的快乐。这就像是住在租来的房子和住在自己家的区别。而且我还是一个人住,所以感觉好极了。 这同时也激发了我写作的欲望,之前的每周写作计划总是一拖再拖。现在有了博客,可能还会拖,但我想会好一些的:)

域名vacantbox,本来想注册的是emptybox,但已被注册。我把这个博客当作一个属于我自己的空盒子,但现在似乎变成了空虚的盒子。也罢,就让我来慢慢填充这个空虚的盒子吧。

博客名普通的我,没什么特别含义,仅仅是字面意思。一直都不太喜欢起名字这种事,我觉得这是一种定义或表达自己的行为,但这行为本身就代表着限制,即不自由。为了弥补名字带来的不自由,每个人都需要把自己的思想和才华释放出来,以弥补名字的限制和它被他人所理解和赋予的狭隘观点。所以每个人都是将自己的被名字所代表的点展开成面或空间的普通人,只不过展开的维度不同,所见的世界也不相同。所以才会有那么多的争吵和矛盾。这个博客也是这样的一种展开,并且希望以此得到相同维度的人的关注和认同。 当然,也许只在自己内心世界里展开,对外永远保持神秘和距离才是最美妙和伟大的事情。但我现在做不到,如博客名所言,我只是个普通人而已。