你好,欢迎光临我的博客!

我是一名热爱计算机的学生,喜欢Python,Java,Linux,js/css/html. 支持自由软件,热爱开源,这是我的github。喜欢电子游戏,我的psn帐号是CenterRight喜欢暴雪的游戏:war3,sc2,炉石。我还是桌面游戏爱好者,喜欢狼人和龙与地下城。喜欢听音乐,我在网易云音乐的帐号是低俗听众喜欢乔治RR马丁、《饥饿游戏》、《布达佩斯大饭店》、爱德华诺顿、姜文和昆汀、The Last of Us。我还对历史,文学,经济学和摄影感兴趣。

这个博客用来分享我的心得,学到的知识,对一些书、电影和游戏的评论。这个博客不会讨论盗版以及破解软件。除特殊说明外均采用CC0创作协议(任何人可以自由地复制,修改,分发和演出——甚至用于商业目的,而不必署名)欢迎转载但是建议保留原文链接以让读者看到最新的版本。本站所有内容仅代表本人观点,与我的雇主无关,并且会永远保持独立性不受任何组织和公司的影响。

如果我们有共同兴趣,或者你遇到了麻烦,可以通过右边的电子邮箱联系我。也欢迎留言和订阅!

自行更换卡西欧电子表电池

高中的时候从亚马逊买了一块卡西欧手表,型号是SGW-400H,电子指针双显的,还带压强和温度传感器。说起来,也服役六年了,卡西欧的质量真是好。最近突然发现它没电了,在网上查了一下,去徐家汇维修需要60元,又在淘宝搜了一下这个型号的电池,只需要27元,作为工科生,这趟路费和手工费省了。

淘宝买零件这种东西真是实惠,发来一看,竟然是两块电池,还附赠这么多工具和防水膏。

一般的电子表都不用拆表带的,直接卸下螺丝就可以打开(有些机械表可能要掰开的)。

打开之后,发现电池后面贴着一行提示“After battery replacement, contact AC with (-) using tweezers.”意思是换过电池之后,要用镊子把负极和AC短接一下。虽然不明白是什么,但是网上说不这么做可能会有奇怪的事情发生。写AC和-的地方很好找,都是小孔,标的很明白。我这次更换电池并没有短接,一切正常。

接下来的换电池步骤分三步:打开电池盖,换电池,合上电池盖。

开电池的地方是没有弹簧的,需要用镊子强行打开。

换好电池之后,把黑色的垫圈按照轨道铺好(见上面的图),涂防水膏。不用太多,湿了就好。垫圈很软,涂的时候很容易活动,需要有耐心。

涂好之后,盖上盖子,上螺丝。完成。

 

 

微信和telegram

使用telegram一段时间之后,深深地爱上了这款软件。第一次得知telegram,是通过这篇比较有名的文章——《Telegram传奇:一个关于俄罗斯富豪、黑客、极权和阴谋的创业故事》。当时下载下来,身边几乎没有朋友使用,就删掉了。最近发现telegram开放了机器人的api(其实是上一年的事情了),又重新下载来,写bot玩儿,顺便推荐给几个朋友一起用一用。发现原来这是如此优秀的一款软件!对比国内最火爆的微信,简直完爆。

我个人信奉的一个哲学是:做一件事,做好它。从软件来说,一个软件应该把应该有的功能做到极致,对于不属于自己的功能,交给其他专业的软件去做。很显然,telegram和微信,就是两个不同的典型。

微信是一个“巨型”的app,目前,微信6.5.8版本是183M,而这时候的telegram(3.18)是64M。其实,这还是压缩之后的,一般下载微信之后使用一段时间,微信占用的内存就会上升到几G,除了聊天资料之后,应用内很多模块都是web形式提供的,可以在app安装之后从服务器在下载。

微信的野心很大,除了聊天,还有公众号,有游戏,发“朋友圈”,甚至还有小程序,这几乎想去替代一个操作系统了。而telegram呢,除了聊天,再没有其他功能了。

既然大家都是IM软件,那么聊天功能,这两家的表现如何呢?随便一想,就可以数出一堆telegram完爆微信的地方:

  • telegram提供搜索功能,搜索的时候直接定位在信息中,所见即所得,可以从日历中选择日期搜索,可以直接在分享过的[links,files,media]中搜索,微信的搜索结果展示在一个列表中……
  • telegram在群组聊天中可以选择reply某一条信息,forward某一条信息(会带上原信息的主人),而微信,你转发的就成了你的,在群聊中更是混乱,在说什么都不知道。
  • telegram可以删除(为收信人删除)信息,可以编辑发送过的信息。而微信……你可能会尴尬的被人问,“你到底撤回了什么?”
  • 打开telegram的时候,你停留在上次看到的地方,就像标签一样,可以往下翻直到最新的信息;而微信,是让你从下往上翻的……如果一段时间没看群聊,再回来的时候你发现自己已经淹没在了信息里。

telegram的端对端通讯功能

关于聊天,有一个最重要的功能。今天的很多IM软件(比如whatsapp),都实现了IM的基本功能——端对端通讯。也就是不经过服务器直接由发送方发消息到接收方。而微信,不管由于技术方面或者由于政策方面,目前没有、将来也不可能有这个功能。

除次之外,界面上,微信自创一套界面,还要求很多基于微信的小程序、web app都遵守它的界面规范,而telegram完美符合google和苹果的界面规范。什么是美,大家都心里有数。平台方面,你也可以说微信的web端就是支持全平台了,但是telegram,有linux版,mac os app,ios,android,chrome app,windows桌面版,而且都是适配各种系统界面,功能一致的。微信的桌面版好像不能处理红包类型的消息和gif吧?有一点我恨不能忍受的是,为什么别的地方登录还需要手机去扫个码呢?我手机没电了想用电脑微信也用不了。

开放是互联网的核心精神。微信要做的,却是与开放背道而驰。小程序,公众号,朋友圈,这些都很难被搜索引擎收录。大概是想自己做一个独特的互联网出来吧。能把url设计成这个样子的app,可能从一开始就没想过“开放”二字。

微信公众号发布的文章冗长的url

而telegram,你可以通过url分享任何东西(url在微信中会先经过微信服务器然后跳到目标url),而且提供了bot这种好东西。在我看来,bot比微信公众号、服务号、小程序高到了不知道哪里去。用bot你可以开发出无数好玩的东西出来(甚至可以用它来收发微信消息),小程序能干的事情它都能干,而且权限也比小程序高,你也可以写一个发布资讯的小程序,完美的“公众号bot”,比如techchurch,就有官方的bot。众所周知,申请公众要、服务号,要提供一大堆个人资料,审核繁琐,比如这位。而申请一个telegram的bot呢?简单到不可想象!telegram里面有个botfather(对,长的很像god father!其实botfather也是一个bot),你只要告诉他,你想要一个bot,就完成了……就是这么简单。

申请一个新bot只是一句话的事儿

bot father

有人可能会说,这么好用有什么用,微信用户是telegram的几百倍?我想说,可能人家就没想做成微信那样,看看《Telegram传奇:一个关于俄罗斯富豪、黑客、极权和阴谋的创业故事》这篇文章就知道了。Twitter市值已经落后weibo40多亿了,但是那又如何呢?还是改变不了weibo是一坨屎的事实。好歹twitter不会迫于淫威删用户内容,weibo呢?先做到不随意给用户加关注,乱发广告再说吧。

屎就是屎,就算你造一堵墙,把好东西都档在外面,用臭味覆盖了整个房子,把房子熏成厕所,我也不承认这坨屎好。

 

部署Sentry

sentry是一个手机错误日志的系统,用django写的。之前我的一个django网站使用的logging来记录错误,然后将ERROR级别的错误通过邮件发送到管理员邮箱。后来发现这么搞不太好,不知道错误发生的次数,信息也比较少,用sentry能收集到ip,浏览器等更多的信息,于是决定改用sentry。

sentry是独立于你的项目的,先安装好sentry,跟你项目无关。sentry正常运行之后,登录,然后设置一些跟你的项目有关的东西。

直接使用pip安装就行了。当然,推荐使用虚拟机安装,这里就不多说了。

安装的过程中,我报了这个错误。我报了一个和postgres有关的错误,我决定使用MySQL,就不理这个,然后安装pyhton-mysql.

到这里,sentry的安装就完成。和wordpress一样,下面进入系统进行设置。

使用sentry init命令,会初始化一个~/.sentry,在这里会保存必要的设置。

然后使用sentry start命令开始设置并启动web服务(以后就不要使用这个命令启动了,使用sentry run web)。

接下来就可以进入sentry了,用浏览器打开~/.sentry/sentry.conf.py里面写的地址,就可以进行相关设置了。

如果在界面的最上面看到“Background workers haven’t checked in recently…..”的提示,说明是sentry的celery没有正常启动,使用”sentry run cron”和”sentry run worker”启动一下。

如果使用root账户运行的,会遇到以下提示(不建议使用root账户):

非要使用root的话,export C_FORCE_ROOT=”true” 就可以了。

如果django之前设置了logging,sentry是捕捉不到的,将logging相关的设置替换成以下(官方模板的,也可以自己修改):

 

 

吐槽一些神奇的政府网站

博客好久没更新了,最近非常忙。到德国交换落下的课必须这学期补,还有论文要写,加上实习,(其实还有每天忍不住玩守望先锋的时间)基本上时间就塞满了。最近实习的主要内容是写爬虫,工作有点无聊,技术上没有啥挑战,但是要处理很多边界值这种情况。也见识了很多让人哭笑不得的网站。

爬的目标很多是政府网站。在我的印象中,政府网站和大学官网是奇葩一般的存在,对了,国有公司的官网也算是吧。这种网站访问量不少,但是用户体验非常糟糕,看了页面的源代码,你都不知道这种网站是怎么写出来的,怎么维护(所以一般不维护吧……)。

比如说,某网站的css全部写在页面内,,<p>标签中穿插着各种<span> <font>,整个页面没有使用一个css class!这个页面的开发维护人员,一定惊为天人!于是这个页面的爬虫,只好写成了这样子……

还有一个神奇的网站,爬虫写好的时候,发现抓不到数据。打开网页一看,数据没了!网页是能打开的,但是没有数据!留下我一脸懵逼不知所措,回家睡了一觉之后发现,又能打开了!于是我发现了规律,上午9点到下午5点是能打开的,就在调度上让这个爬虫在每天的11点运行,并注释:此网站朝九晚五,估计是运行在工作人员自己的电脑上。

又想起来一个,一个公布著作权的网站,列表页打开特别慢,但是详情页能秒开。页数显示,这个网站的列表页有五百多万页,于是我想,这个网站的页数大概是把所有的数据取出来计算一下数量,才会这么慢吧……

除此之外,这些网站的URL混乱不堪,页面结构杂乱无章,安全方面更不必说了,使用HTTPS的一个都没有,却基本上都会有被时代抛弃的flash。这都是政府的网站,稍微拨点款找个靠谱一点的外包公司,也不至于这样啊。

 

理解Python的with语句和上下文管理器

With语句的语法和原理

基本语法

with是用来操作上下文管理器的。

上下文管理器(Context Manager):支持上下文管理协议的对象,这种对象实现了__enter__()__exit__() 方法。上下文管理器定义执行 with 语句时要建立的运行时上下文,负责执行 with 语句块上下文中的进入与退出操作。通常使用 with 语句调用上下文管理器,也可以通过直接调用其方法来使用。

换句话说,实现了__enter__()__exit__()的就是上下文管理器,就可以使用with语句。

使用with语句,会先执行上下文管理器context_expression的__enter__()方法,如果该方法有返回值,将返回值赋值给as的变量,然后执行with语句块的内容,最后执行with-body

上下文管理器的基本语法:

将一个上下文管理器用try-catch的方式实现:

原理

with的执行过程如下:

首先,执行__enter__(),返回值赋值给value

然后执行withwith-body代码块,如果上一步有value,则使用。

如果with-body执行过程中发生异常,执行__exit__()方法。没有发生异常也会执行__exit__()方法,区别就是exc变量。

如果发生异常退出的,__exit__()如果返回True,则异常被忽略;否则异常被重新抛出,交给with外面的代码处理。如果__exit__()发生了异常,则会取代with-body中的异常抛出。

要处理异常时,不要显示重新抛出异常,即不能重新抛出通过参数传递进来的异常,只需要将返回值设置为False就可以了。之后,上下文管理代码会检测是否 __exit__() 失败来处理异常。

自定义上下文管理器

定义一个实现了__enter__()__exit__()的对象即可。

  • context_manager.__enter__() :进入上下文管理器的运行时上下文,在语句体执行前调用。with 语句将该方法的返回值赋值给 as 子句中的 target,如果指定了 as 子句的话
  • context_manager.__exit__(exc_type, exc_value, exc_traceback) :退出与上下文管理器相关的运行时上下文,返回一个布尔值表示是否对with-body过程中发生的异常进行处理。参数表示引起退出操作的异常,如果退出时没有发生异常,则3个参数都为None。如果发生异常,返回True 表示不处理with-body的异常,否则会在退出该方法后重新抛出异常以由 with 语句之外的代码逻辑进行处理。如果该方法内部产生异常,则会取代由 statement-body中语句产生的异常。要处理异常时,不要显示重新抛出异常,即不能重新抛出通过参数传递进来的异常,只需要将返回值设置为 False就可以了。之后,上下文管理代码会检测是否 __exit__() 失败来处理异常。

contextlib模块

这个模块提供了很多使用的装饰器和函数。

装饰器 contextmanager

装饰一个生成器函数,函数被装饰过后,返回一个上下文管理器对象。

yield之前的语句,作为__enter__()执行,之后的语句作为__exit__()执行。yield作为__enter__()的返回值。

函数 nested

nested可以将多个上下文管理器组织在一起,避免使用嵌套 with 语句。

类似于:

上下文管理器 closing

closing会将包装的对象返回给as,并在with代码块结束的时候调用对象的close()方法:

一个小问题

之前有点疑惑,为什么python内置的open()既没有被@contextmanager装饰器装饰,又不是一个对象,为什么可以使用with语句呢?

还在staskoverflow提问了这个问题。

原来,open()返回的是一个继承自IObase的对象,这个对象也是一个上下文管理器,所以就支持with语句了。

参考资料

  1. Expert-Python
  2. [翻译] 理解Python的With语句
  3. 浅谈 Python 的 with 语句(非常好的资料)
  4. 如何正确理解关键字”with”与上下文管理器