编译安装Vim

使用apt-get或者别的包管理工具安装的Vim可能不支持一些特性,比如python。通过vim --version可以查看所支持的所有特性。如果想要Vim支持Python或其他(即将Python编译进Vim),就需要重新编译。编译的步骤如下:

1.准备一些可能遇到的库

先在系统中安装好可能需要的库,如果你不知道准备什么,可以等到第三部configure报错的时候,缺少什么再回来安装。

2.卸载原来的Vim

依次执行下面的命令卸载。

3.下载Vim源代码,解压

下载地址是:ftp://ftp.vim.org/pub/vim/unix/vim-7.4.tar.bz2 可以通过wget命令直接下载,也可以下载别的版本。

4.make安装

先执行config,参数可以根据自己的需要修改。

这个时候如果你缺少库,就会得到提示。比如我就遇到了下面这个错误:

查了一下,是缺少ncurses-dev,使用sudo apt-get install ncurses-dev直接安装就可以了。

最后make,搞定。

 

 

维护博客:手动升级wordpress,全站HTTPS

最近wordpress升级到4.7了,我有点强迫症,一直都跟着最新的版本。以前很好,只要点击立即升级,马上就升级好了,现在不知道为什么,两个周之内我试过很多次,都是失败的。今天实在是受不了了,就手动更新了一下,记录一下更新的步骤。

  1. 备份数据库(废话)。
  2. 禁用所有的插件,这是官方推荐的,照做(注意如果是升级到2.7那么这一步是必须的,不过现在没有人还用这个版本了吧)。
  3. 下载最新的版本,解压。
  4. 用FTP上传新版本的wordpress,这里最好先删除wp-includes, wp-admin两个文件夹,因为上传的时候文件是可以直接覆盖的,文件夹覆盖可能出现问题,注意不要误删了wp-content,这个文件夹存放的是你的静态文件。我用linux的命令行登录ftp上传文件显示的是553 Could not create file.,也不知道为什么,删除是有权限的。然后视图安装filezilla,去管网一看,太麻烦了……需要自己编译安装呢!于是懒得我就去问joyme现在有没有时间帮我上传一下,他说可以用apt-get安装filezilla啊,好吧,竟然不知道图形软件也可以通过apt-get 安装。
  5. 上传覆盖之后,还需要更新一下数据库。方法是访问update页面,其实我们直接登录admin就可以,它会提示你访问的。
  6. 更新完成,讨厌的升级提示消失了!

期间我还遇到一个问题:admin首页的仪表盘都不见了!变成了四个空的框,也没有上面的“显示选项”按钮可以让我调出来内容。后来发现是wp-cache搞得,直接删除缓存,搞定。以后遇到问题都可以先删除缓存试一下。

升级好了之后,我打算部署全站https。这是2017年的计划之一。

话说西部数码有点坑啊,不能自己部署,需要交100块钱让他们的工程师部署,我觉得好坑,两分钟就能搞定的事情。好吧,加上买ip的钱,阿里云便宜多了,速度也快多了。不过西部数码的好处是不用备案,他们的客服帮解决问题也挺省心的。

扯远了。回到https上来。证书我是在知乎上面看到大家说腾讯云只要验证了域名是你自己的,就可以颁发免费证书。可以,这很免费,我回头试了一下接着Firefox就把你标为不安全网站了。好吧,回头得搞一个靠谱的,花点钱就花一点吧,毕竟都2017年了,要普及https。

拿到证书和私钥,这部分的部署就和wordpress没关系了,也不是很麻烦,我交了100块没操作,这部分就略过去。

回到wordpress,要将站点的域名设置一下的,不然内链会有很多出错。我的很多静态资源都出错了,也不知道怎么回事,最后的解决办法是使用sample ssl的插件解决了事。这个软件软件推荐在部署之后去google的console和analytic上面设置一下,不是很麻烦,跟着教程做一下。

然后就是做一下全站的https了,到这里就有点心疼了。首先,国内所有的分享插件都是http代码实现的,当然不能用了。不过我发现也没有几个人把我的文章分享到别的地方嘛……删掉就删掉吧,分享也可以用链接。

七牛的cdn我没有https的,也不能用了。以后所有的流量都要走自己的。也还好,我的流量不是很大,目前来说不算什么,就是速度有点慢了。

最心疼的是微博秀了和豆瓣的推荐了,我一直把微博当博客的展示插件,作为短博客来写的,所有发在微博的东西都会以在博客的显示为首要目的,这下子没有了。不过微博不提供https也是坑啊。豆瓣可以自动显示我最近看过的书、电影、音乐并且打5分以上的,也没有了。有好多人问过我这个很好看,是怎么做到博客上的,现在不能用了有点可惜。

还有就是disqus,这个是个好东西啊,国内的评论插件都不好看,被disqus甩了八十条街,而且不支持https。disqus的评论在wordpress也会有,不像别的插件完全把你的数据拿走了。关于disqus的优点,比起国内的评论插件来,能说一本书。可惜的是这货被墙了,只好用自带的评论系统了。

这样,全站https也算是显示了。下一步应该去买一个更可靠的证书,然后博客重新搞一搞,针对seo做一下,以后多写一点文章。


更新:关于Firefox对证书不信任的问题。通过腾讯云平台申请的免费的证书是TrustAsia DV SSL CA – G5,直接部署这个证书,Firefox依然会将你的网站列为危险网站。但是不代表这个证书有问题,是中间签发机构的问题。解决方法是:下载Startssl的根证书,然后放到自己的证书的后面,Firefox就认为这个证书可以信任了。

参考:解决startssl证书在android手机浏览器或Firefox不信任的问题

完美!治好我的强迫症。如果后面再看到站内存在混合资源的话,估计是我什么地方手贱用了http的绝对链接,看到一个改一个就好了。

 

对PyObject的一点理解

很久之前看过一篇有关Python的list的博客,里面提到,Python中list的数据结构是这样的:

我很不理解的是,list完全可以存储×ob_item就可以了啊,为什么要存放××ob_item呢?

只要list的每一个元素存放的是指向PyObject的指针,就已经可以实现增删改查了,维护一些指向PyObject的指针就可以了,而且指针只有一层,还比“指向指针的指针”更快一些。百思不得其解,去stackoverflow上面提问,有个人回答,这样的话,如果要修改list的值,只要将指针指向另一个“指向PyObject的指针”就可以了。但是我觉得,即使是存一层指针,repoint也不是很麻烦。

后来自己就想了很长时间,跟朋友吃饭讨论过,跟张哥也讨论过。

昨天晚上,我感觉自己有点理解了。

首先,PyObject肯定是不能拿来用的,因为这就是文件系统的blob一样,我们用的是指向它的node,看他的文件块没有意义。所以一般来说,我们用的是×PyObject来操作Python对象。换句话说,我们基本上不会去直接搞PyObject,×PyObject一般是我们能获得PyObject的唯一方式。那么如果在list里面存放一层指针,即×PyObject的话,就差不多是复制这个对象进去了(虽然存放的也是指针)。参考下图:

PyObject

这个时候,如果从list的索引改了PyObject,那么×PyObject也会受影响,是指向了同一个对象(这个地方和××PyObject)是一样的。但是考虑这样一种情况:

假如是我想象的list存放的是×PyObject的话,我们将tom添加到list之后,重新给tom赋值了一个对象,也就是说,tom指向了另一个对象。但是li中的tom是直接指向一个对象的。也就是说,tom的repoint就和li中的tom关联不到了。

可能说的有点绕,和指针相关就比较麻烦,简单来说,就是:如果list存放的是×PyObject,那么变量重新指向别的对象的话,list存放的变量还是指向原来的对象,我们无法通过引用给list中的元素重新指向了(只能通过list的索引重新指向)。这就点像软链接和硬链接的区别。

但是如果存放的是××PyObject,那么引用(×PyObject)指向的什么,数组里面就存放的什么:

PyObject -pointer

另外,如果list存放×PyObject,那么list的元素改变之后,旧元素很可能没有指针指向它了,很可能被作为垃圾回收。

以上,是我这几天的理解,没有经过验证,很可能都是错误的。

 

Python 为什么list不能作为字典的key?

很多Python初学者经常会有这样的疑问,为什么Python有tuple(元组)和list(列表)两种类型?为什么tuple可以作为字典的key,list不可以?要理解这个问题,首先要明白python的字典工作原理。

1.Python的字典是如何工作的

在Python中,字典也就是一个个的“映射”,将key映射到value:

为了实现这个功能,Python必须能够做到,给出一个key,找到哪一个value与这个key对应。先来考虑一种比较简单的实现,将所有的key-value键值对存放到一个list中,每当需要的时候,就去遍历这个list,用key去和键值对的key匹配,如果相等,就拿到value。但是这种实现在数据量很大的时候就变得很低效。它的算法复杂度是O(n),n是存放键值对的数量。(关于Hash表具体的工作原理,可以参考我的这篇文章

为此,Python使用了hash(哈希)的方法来实现,要求每一个存放到字典中的对象都要实现hash函数,这个函数可以产生一个int值,叫做hash value(哈希值),通过这个int值,就可以快速确定对象在字典中的位置。然而,由于Hash碰撞的存在,可能存在两个对象的Hash值是相同的,所以查找字典的过程中,要比较hash值,还要比较value的值。

这个查询的大致过程如下:

要使这个查找过程正常工作,hash函数必须满足条件:如果两个key产生了不同的hash value,那么这两个key对象是不相等的。

否则的话,hash value不同,对象却相同,那么相同的对象产生不同的hash value,查找的时候就会进错桶(step 2),在错误的桶里永远也找不到你要找的value。

另外,要让字典保持高查找效率,还要保证:当两个key产生相同的hash value,那么他们是相等的。

这样做的目的是,尽量满足每个hash桶只有一个元素。为什么要这样呢? 考虑下面这个hash函数。

这个hash函数是满足上面我们谈的第一个条件的:如果两个key的hash value不同,那么两个key对象不相同。因为所有的对象产生的hash value都是1,所以不存在能产生不同hash value的key,也就不存在不满足的情况。但是这样做的坏处是,因为所有的hash value都相同,所以就把所有的对象分到了同一个地方。查找的时候,进行到第三步,遍历的效率就变成了O(n).

Hash函数应该保证所有的元素平均的分配到每一个桶中,理想的情况是,每一个位置只有一个元素。

以上两个原则,第一个保证了你能从字典中拿到要找的元素,第二个保证了查询效率。

2.字典Key要满足的要求

经过上面的讨论,我们应该明白Python为什么对字典的key有这样的要求了:

要作为字典的key,对象必须要支持hash函数(即__hash__),相等比较(__eq__或__cmp__),并且满足上面我们讨论过的条件。

3.List为什么不能作为key

至于这个问题,最直接的答案就是:list没有支持__hash__方法,那么为什么呢?

对于list的hash函数,我们可能有下面两种实现的方式:

第一种,基于id。这满足条件——“如果hash值不同,那么他们的id当然不同”。但考虑到list一般是作为容器,基于id来hash可能会导致下面两种情况:

  • 用相同的list作为key去字典中找某个元素可能会得到不同的结果,因为是基于id hash的,所以即使他们的内容相同,字典依然将他们作为不同的元素对待。
  • 创建一个一模一样的list用字典查找永远会得到一个KeyError。

第二种,基于内容。tuple就是这样做的,但是要注意一点,tuple是不可以修改的,但list是可以修改的。当list修改之后,你就永远别想再从字典中拿回来了。见下面的代码。

鉴于两种实现的方式都存在一定的副作用,所以Python规定:

内置的list不能作为字典的key.

但tuple是不可变,所以tuple可以作为字典的key。

(2018年1月2日更新,上面我说tuple不可变可以作为字典的key,这句话并不是完全正确的。tuple只是相对不可改变的,如果tuple中有元素是可变对象,那么虽然tuple不可改变,那么其中元素所指向的对象是可变的,所以同样会出现上面“list不能作为字典的key”这个问题,即含有可变对象的tuple也不能作为字典的key,举个例子就很好懂了。)

4.自定义的类型作为字典的Key

用户自定义的类型就可以作为key了,默认的hash(object)id(object), 默认的cmp(object1, object2)cmp(id(object1), id(object2)),同样是可以修改的对象,为什么这里就没有上面说的问题呢?

  1. 一般来说,在映射中比较常见的需求是用一个object替换掉原来的,所以id比内容更重要,就可以基于id来hash
  2. 如果内容重要的话,自定义的类型可以通过覆盖__hash__函数和__cmp__函数或__eq__函数来实现

值得注意的是:将对象和一个value关联起来,更好的做法是将value设置为对象的一个属性。

 

Django中null和blank的区别

Django的Model可以设置字段的null属性和blank属性。

null属性是针对数据库而言的,null=True将设置数据库的COLUMN为NULL(或者NOT NULL),而blank为True将不会影响数据库的结构,依然是必填。但是在Django里面,是可选的。即Form不会是required,Django自带的admin页面不要求必填了。

具体作用到数据库,是这样:

在 PostgreSQL 9.4 的结果如下 :

MySQL 5.6 的结果如下 :

可以看出,数据库的字段是否可以为空完全取决于null属性,和blank没有关系。

那么为什么需要需要两个变量分开呢? 想象这样一种场景:我们需要用户的forms必填某一个选项,但是是否存储到数据库,就取决于其他的一些情况了。再如,我们需要用户必须输入,但是我们用其他方式(除了Django之外,例如用shell维护数据库的时候)时,可以不用设置这些字段,这时候就可以设置null=True,blak=False。

另外要注意的是,有些字段是不适合设置null或blank的,参考下表:


参考资料:

  1. differentiate null=True, blank=True in django
  2. Django 1.6 最佳实践: 如何正确的使用和设置Database和Model