python-snappy编译安装遇到的问题

最近使用snappy压缩数据,编译python-snappy的时候,因为没有root权限,只好自己来指定链接的地址。

build的时候发现没有可以指定的选项,只好通过指定CPLUS_INCLUDE_PATH到snappy库的include目录,指定LIBRARY_PATH到snappy的lib目录。

成功安装snappy。

之后引入snappy模块的时候,发现没有安装ffi库,真是杯具呀。编译libffi到指定目录,启动python发现python找不到这个库。

python不是查找LIBRARY_PATH和CPLUS_INCLUDE_PATH的,是通过查找C_INCLUDE_PATH和LD_LIBRARY_PATH来找到对应的头文件和库文件的。

所以我们需要把libffi和snappy的路径指定上:

snappy终于可以用啦。

如果需要每次都生效就把export语句放到.bashrc中就可以了。

php使用反射访问私有元素

php的反射机制可以让使用者获取到一些元素的运行信息、状态等,我们可以通过ReflectionClass导出类、访问其元素、获取类定义信息等,可以通过ReflectionFunctionReflectionMethodReflectionProperty等类访问函数、方法、属性之类元素的信息。

下面是一个可以访问私有元素的类,通过ReflectionMethodReflectionClass实现:

反射类比较强大,用类的方法实现也更加直观。为我们进行一些简单测试或者工具制作上提供了不小的便利。

pymongo保存snappy压缩数据

在使用python snappy压缩以后的数据,保存到mongo时报字符串编码错误,错误内容和下面的差不多:

bson.errors.InvalidStringData
strings in documents must be valid UTF-8

这时候可以使用bson binary格式来保存这类数据:

以上,希望能对你起到帮助。

几个语言中的迭代器

上次有朋友说python的迭代器很好用,就是不好理解,我说其实php也有迭代器的,只是很多人不知道而已。

python迭代器:

先说说python的迭代器,python的迭代器使用yield关键字来实现,可以被for调用。

还是来拿读文件来说事,我们有一个文件,里面的数据都是TAB分隔,如果我们想实现一个一行行读取的库核心的地方可以使用迭代器来写:

tab文件(html输出后估计tab变成了空格,复制的同学请注意):

迭代器代码:

这里涉及迭代器的部分在于read方法中的yield迭代器,虽然是for循环,在yield调用一次以后会挂起等待下一次调用yield,所以很多人在这里需要理解很久。所以yield在while内自然也是一样的效果。

继续阅读

堆排序

上次写了个快排的文章,果不其然被大家鄙视了。大概平时是一个写脚本的,这东西也不会了,大学时代还能帮别人替考c语言,现在连c都不写了。

回归正题,这里使用二叉堆,二叉堆是一个近似的完全二叉树,在很多地方都会用到这个结构。

通常使用数组来表示一个堆:假设数组第一个元素为根节点,那么它的左孩子节点就是第二个元素,右孩子节点为第三个元素。以此类推,假设一个节点是数组的第n个元素,它的左孩子节点就是第2n个元素,右孩子节点就是2n+1,可以使用floor(n/2)来获取其父节点。

二叉堆分为最大堆(MAX-HEAP,大顶堆)和最小堆(MIN-HEAP,小顶堆),最大堆就是父节点的值大于或等于子节点值的堆,所以根节点应该是最大的节点,最小堆反之。这里使用了最大堆。

继续阅读

php的traits和单例

最近和同事聊天时发现很多同事并不了解php的一些特性。有时他们会说python的某些特性非常有趣,确实,但我提到php中也存在一些类似特性的时候,他们表示并不了解,于是考虑写几篇关于php特性的文章。如果其他语言有这类特性,我会尝试着对比来讲解。

phper们应该都知道在5.4以后增加了一个新特性叫做traits,其文档如下:

http://php.net/manual/zh/language.oop5.traits.php

traits感觉像是让你更方便的复制粘贴代码,这些代码统一的管理着。你可以使用trait_exists方法来检查traits是否存在,使用class_uses列出所有使用traits的方法。

网上有些文章吐槽traits这个特性破坏了封装或是如何,我的层次不高,只能默默表示有时候用这东西还是比较舒服的。

比如我们写单例方法,这东西我们的项目中经常性的用到:

为了不让别人初始化,我们需要控制构造函数好克隆方法的权限,然后让类自己检查和初始化自己。

继续阅读

说说python的__del__方法

python中提供一个__del__方法,这个方法在实例释放的时候被调用,被称为析构器。

但最近使用中发现这个析构器和其他语言的析构方法不太一样,存在着一些不确定性。

比如我们在php中可以这样销毁一个对象:

此时php的析构方法__destruct()被调用。

python中我们经常会这样做

标量的销毁是没有任何问题的,但是对于对象来说,因为存在着比较复杂的引用关系,del只是把对象的引用计数减一,而不是直接调用__del__方法,这导致del方法没有达到预期内的效果。

而且,在对象的引用计数为0的时候,垃圾回收也不一定会回收此对象,而__del__方法在垃圾回收的时候才被调用。

同时,使用了__del__以后,python似乎不再追踪和释放循环引用(这点还没有经过确认)。

更多关于__del__的问题可以参考这个stack overflow question : how to call the __del__ method ? 

所以,当我们想像某些其他语言一样在调用完以后执行一些小动作的时候,比如关闭文件句柄、写点小日志之类。可以考虑使用python提供的with方案。下面是一个with的调用方法:

这个demo比较简单,python的open也支持with,但这个重复造的不完整轮子也比较容易解释with结构。这段代码在with语句结束的时候会调用__exit__方法。__enter__方法的返回值会返回给as作为f的值。

当然,__del__早晚会被调用的,如果你不着急而且控制得当,应该是没有任何问题的。

快速排序

前几天有人问起快排,我心想这不难呀,把原理讲完了以后发现自己写不出来……回去默默看着导论用ruby写了一个……

快排使用分治思想。最重要的是分区:取一个基准值,比基准值小的放到数组左边,比基准值大的放到数组右边,基准值自己放到中间。然后对左边和右边的数进行再分区,如此递归直到全部排列好。

基准值是从数组中获取到的,你可以自己选择,或者随机选择一个。如果是随机取基准值的快排,因为无法确定命中最好情况还是最坏情况,所以大量的排序情况下会趋近于期望值。

快排保持着两个变量或者指针,一个是当前迭代到的key,一个是当前需要交换的key。如果达到交换条件(比如迭代到的key对应的值相对比对值小)就和需要交换的key进行交换。这两个变量或者指针可以按照自己的意愿进行调整,不管是从左到右,还是从右到左。

这里要注意的是当前需要交换的数是什么,我们假设比基准数小的数叫小数,比基数大的叫大数,排列在数组中最左边的大数叫最左大数,那么在程序中和基准数比对时:

  • 当前数是小数,交换当前数和最左大数(此时最左大数可能被移到了其他大数右边,往下一位找到下最新的最左大数)
  • 当前数是大数,进入下一轮
  • 和基准值相等,这种情况算大数小数都是可以的,因为后面迭代时会重新排到正确位置

所有数字比对和移动完毕后,把基准数和最左大数交换,这样基准数就在所有数字的中间了。

下面是增加了随机的ruby版本

关于redis的传输协议

很久之前就想写这篇,但是因为时间问题一直也没有弄,先粗糙整理一篇。

redis的传输协议(RESP)

redis的协议总体算比较简单,第一个符号表示回复的类型:

"+" 表示是一个简单字符串,一般都是状态消息,比如输入PING命令
"-" 错误返回使用减号,比如输入一条错误命令
":" 返回数字,比如使用INC命令
"$" 表示返回一条字符串安全的字符串,最长512M,比如使用GET命令
"*" 返回的是一组数据,比如使用SMEMBERS命令

如果是"+"、"-"或者":"后面紧跟着消息体,然后跟一个CRLF,CRLF其实就是"\r\n",消息结束。

[+-:]<msg>CRLF

比如:

  •  +PONG\r\n
  • -unknow command 'foobar'\r\n
  • :10\r\n

剩下的两个个形式在第一个符号后面跟着对应的长度表示,然后是CRLF,接着是消息体表示,最后CRLF结尾:

[$*]<LEN>CRLF<BODY>CRLF

这里的<LEN>如果是结果是字符串则表示字符串长度,如果是一组数据则表示元素个数。<BODY>是消息体,如果是字符串则表示字符串长度,如果是一组数据则使用对应的单条数据的表示形式填充(:|$等数据)。如果长度是-1则表示没有这条数据。比如:

  • $6\r\nfoobar\r\n
  • $-1\r\n
  • *0\r\n
  • *2\r\n$3\r\nfoor$3\r\nbar\r\n
  • *5\r\n:10\r\n$-1\r\n$3foor\r\n

redis协议可以参考这篇文档:redis protocol

这里还有篇中文的:通信协议

继续阅读