可可熊的窝

Tag Archives: Python

Python与Lua分别实现一个计数器

IN:Lua, Python   Tags: ,    Comments:3

Lua:

>   function newCounter ()
>>     local i = 0
>>     return function ()   -- anonymous function
>>              i = i + 1
>>              return i
>>            end
>>   end
>
>   c1 = newCounter()
> print(c1())
1
> print(c1())
2

Lua同Python类似,也可以嵌套定义函数,不过Lua嵌套函数可以访问上层闭包函数的局部变量,而在这个内嵌函数中这些变量不是全局变量,也不是局部变量,而是一种upvalue,与C语言中的static修饰的变量类似,所以在这里可以利用这个特性完成这个计数器。

Python:

  >>> def counter(last=[1]):
  ...     next = last[0] + 1
  ...     last[0] = next
  ...     return next
  ...
  >>> counter()
  2
  >>> counter()
  3

今天看Lua的时候觉得Python也应该有比较简单的办法写个计数器,找到一篇文章介绍这个小技巧,其中有一句话:

However, if named parameters are given mutable default values, the parameters can act as persistent memories of previous invocations. Lists, specifically, are handy mutable objects that can conveniently even hold multiple values.

Lua作为一个嵌入式(嵌入到其它语言中)的脚本语言,在很多地方与Python类似,这几天在看Programming in Lua 。

03-31
2009

更新PyFetion && getsong

IN:Python   Tags: , ,    Comments:8

给PyFetion加入了HTTP代理的支持,HTTP发送方式中。TCP发送方式也可能会加上吧,使用SocksiPy这个库吧,有时间再说。

改PyFetion的时候发现urllib2的一个问题:
先看下面这段代码:

import urllib2
headers = [("Content-Type","application/oct-stream"),]
opener = urllib2.build_opener()
opener.addheaders = headers
urllib2.install_opener(opener)
print "after install_opener"

ret = opener.open('http://www.dict.cn',data="word=ss")
print ret.read()

抓包发现发送的内容为:

POST / HTTP/1.1
Accept-Encoding: identity
Content-Length: 7
Host: www.dict.cn
Content-Type: application/x-www-form-urlencoded
Connection: close

word=ss

这里我在代码里已经指定了HTTP的header: Content-Type,但是发出去的时候却被改变了。

通过分析urllib2的代码,找到:

if request.has_data():  # POST
    data = request.get_data()
    if not request.has_header('Content-type'):
        request.add_unredirected_header(
            'Content-type',
            'application/x-www-form-urlencoded')
    if not request.has_header('Content-length'):
         request.add_unredirected_header(
           'Content-length', '%d' % len(data))

scheme, sel = splittype(request.get_selector())
sel_host, sel_path = splithost(sel)
if not request.has_header('Host'):
    request.add_unredirected_header('Host', sel_host
    or host)
    for name, value in self.parent.addheaders:
    #这里的parent是opener对象
    name = name.capitalize()
    if not request.has_header(name):
        request.add_unredirected_header(name, value)

urllib2发现如果是POST数据的话自己添加了Content-Type,接着才去追加opener对象中的headers,这时已经有Content-Type了,所以opener对象增加的Content-Type就无效了。

解决办法是创建request对象,在request对象中设置Content-Type:

request = urllib2.Request(url,headers=headers,data=body)

不知道是上面的示例代码写法不规范呢?还是算Python的一个小问题呢?

最近发现周董的不少歌挺好听,于是找个脚本来下载周董的歌(从百度mp3中), getsong就进入了眼的视野,不过不支持下载某个歌手的全部歌曲,俺自己加上去,正在下载周董的歌:

[cocobear@cocobear getsong]$ ./getsong.py -a 周杰伦
正在下载第1首(共104首) 歌手:周杰伦 曲名:她的睫毛
已经成功下载《周杰伦 – 她的睫毛》
…….

不过这会儿断了,getsong好像又有bug了,今天就不折腾了,明天再整整吧,看书,睡觉了。

03-24
2009

更新两个小脚本

IN:Python   Tags: , ,    Comments:4

一个是以前写的导出抓虾收藏的工具,增加了保存抓虾上文章的功能,因为只导出链接有些文章地址可能已经失效。

另一个就是pysdcv,前面文章介绍过了,整理了一下,测试了一下,然后放在了google code上面,直接使用星际译王的词典,查一个单词大概0.15秒的时间:

cocobear@0-0 /home/cocobear/Work/pytool/pysdcv $ make
gcc lookup.c -g -I/usr/include/python2.5 -lz -shared -fPIC -o lookup.so
cocobear@0-0 /home/cocobear/Work/pytool/pysdcv $ time ./pysdcv.py test
*[test]
n. 测试, 试验, 化验, 检验, 考验, 甲壳
vt. 测试, 试验, 化验
vi. 接受测验, 进行测试
【医】 试验, 测验
【经】 检验, 试验, 测试
相关词组:
put sth to the test
stand the test
give a test
take a test
test sb’s ability

real 0m0.164s
user 0m0.143s
sys 0m0.010s

如果是未使用gzip压缩过的dict文件,则0.05秒左右。

03-20
2009

用Python QQ写一个挂QQ工具

IN:Python   Tags: ,    Comments:10

Python QQ是好早以前就有的一个项目,不过因为很久没更新过,以前看到的时候不能登录,所以没怎么关注过,最近代码被开发者放在了google code上面,也做了些改动,目前可以登录,发送,接收消息了,不过不是很稳定。最近看了看这个项目的代码,对整个socket-qq分枝有了全面了解。在代码设计上也学到了不了东西:-)

Python QQ是在Windows上面开发的,所以我在Linux下测试的时候还有不少问题,最近改了改,然后做了个挂QQ的工具给草儿同学,很不完善的,也很不稳定,使用wxPython+threading完成,GUI+多线程确实是很折腾人的,在多线程更新GUI上使用了wx.CallAfter函数,可以查看limodou博客的介绍。

截个图上来:
oqq

先不发布了,继续完善Python QQ。

03-19
2009

发一个Python版的星际译王

IN:C, Python, 编程相关   Tags: ,    Comments:3

sdcv-0.4.2版本的代码有3480行,而图形界面的星际译王更是有N多的代码,俺也写了一个就十几行的Python代码,速度当然比不上sdcv,能差十倍,不过,请注意,sdcv查一个单词是0.01秒,我这个是0.1秒,我不觉得有人能感觉出来差别。

其实我的核心是C语言写的,之所以在速度上没有sdcv快是没有做那么些优化,俺只写了80多行,而且还有不少代码是用作Python封装的。我以前写文章说过sdcv代码写的很麻烦,用C语言可以很简洁的写出来,现在确实做到了,只是结合了Python。我觉得这种模式挺不错,影响速度的核心使用C语言去写,然后主逻辑框架使用Python写,不仅效率不会受影响,开发的速度也提高了不少。(我这个例子Python并没做什么)

static PyObject * lookup(PyObject *self, PyObject *args)
{
    int fd;
    char *file_prefix;
    long file_size;
    long wc;
    char *word;

    char *data;
    const char *p;
    long index_size;
    int offset;
    int size;
    int flag = 0;
    unsigned char *buf;

    if (!PyArg_ParseTuple(args, "slls:lookup",
                &file_prefix, &file_size, &wc, &word)) {
        return NULL;
    }
    char file_name[256];
    strcpy(file_name, file_prefix);
    strcat(file_name, ".idx");
    if ((fd = open(file_name, O_RDONLY)) < 0) {
        printf("open failedn");
        return NULL;
    }
    data = (char *)mmap( NULL, file_size, PROT_READ, MAP_SHARED, fd, 0);
    p = data;
    int i;
    for (i=0;i<wc;i++) {
        index_size = strlen(p) + 1 + 2*sizeof(int);
        if (strcmp(word, p) == 0) {
            flag = 1;
        }
        if (flag == 1) {
            offset = ntohl(*(int *)(p + strlen(p) + 1));
            size   = ntohl(*(int *)(p + strlen(p) + 1 + sizeof(int)));
            //printf("offset=%dnsize%dn",offset,size);
            /*gzFile zfile;
            zfile = gzopen("./dic/stardict-langdao-ec-gb-2.4.2/langdao-ec-gb.dict.dz", "rb");
            gzseek(zfile, offset, SEEK_SET);
            buf = (unsigned char *)malloc(*size+1);
            memset(buf, '', size+1);
            gzread(zfile, buf, size);
            printf("%sn", buf);
            */
            close(fd);

            if ((fd = open("./dic/stardict-langdao-ec-gb-2.4.2/langdao-ec-gb.dict", O_RDONLY)) < 0) {
                return NULL;
            }
            lseek(fd, offset, SEEK_SET);
            buf = (unsigned char *)malloc(size+1);
            memset(buf, '', size+1);
            read(fd, buf, size);
            //printf("%sn",buf);
            close(fd);
            return Py_BuildValue("s", buf);
        }
        p += index_size;
    }

    return Py_BuildValue("s","");
}

static struct PyMethodDef lookup_methods[] = {
    {"lookup", lookup, 1, "lookup(file_prefix, file_size, wc, word)"},
    {NULL, NULL}
};

void initlookup()
{
    (void) Py_InitModule("lookup", lookup_methods);
}

使用C语言对Python进行扩展挺方便的,http://gashero.yeax.com/?p=38#id7这里有个不错的文档。
完了俺整理整理也放在google code上去。

上面的代码中dict文件需要是未gzip压缩过的,如果在压缩过的我使用被注释掉的那段代码在seek的时候速度很慢,又没办法用mmap,所以暂时就先只使用未压缩过的。

02-26
2009

PyFetion更新

IN:Python, 编程相关   Tags: ,    Comments:39

详细的更新请到google code 查看。

  1. get_info()函数参数处理who遗失的情况;
  2. 向服务器以HTTP方式提交密码时使用urllib.quote()编码;
  3. 修改send_msg()函数;
  4. 清理代码中直接退出的exit函数;
  5. 重写__tcp_recv()函数,以前这里有可能会丢失数据,比如好友列表过长;
  6. 增加隐身登录功能,login(True)表示隐身登录。

以前还有人提到增加隐身登录,我看了下08 PC版的飞信,只能是先登录,然后再设置隐身模式,这样的话增加设置隐身模式就没必要了。

至于登出飞信更是没必要了。

09.02.23 Update:

  1. 上次的代码get_uri被我改出错了,修正了一下;
  2. 修改了使用手机号直接发送的方式,因为目前可以使用tel: 13888888888的方式发送短信,不用从联系人中一个一个找了;不过以前似乎这种方式不行;
  3. 修正了获取联系人信息的XML数据,可以完整的获取联系人;
02-20
2009
Page 3 of 712345...Last »
loading...