分类: '编程相关' 的归档
欧拉工程
咳咳,我做为非正常网民网瘾戒除中心的砖家,正式给介绍介绍一下这个欧拉工程。
呃。。。还是请我们的校长──lerosua──来介绍吧~下面引自这篇博文:
欧拉工程是一个用编程来解决一连串数学问题的项目。发现它对训练数学及编程挺有作用的。网上也有许多人做上面的题目并发布自己的算法。
上面共有261题,分几个等级,一级比一级难。我看了第261题的提交,目前只是22个。完成它绝对是时间及精力及耐力及智力的较量。
于是本人决定将此作为一个项目来做,逐步进阶。
骨头与xiooli同学也并肩作战。
我们解决的问题的源码将会发布在以下svn中。欢迎审阅.
http://nrciz.googlecode.com/svn/trunk/projecteuler
其实,之前(几个月前吧)我就已经做过几题了。可以说,正是因为欧拉工程,我才喜欢上python的,当我看到第一题用一句
sum([n for n in range(1000) if n%3==0 or n%5==0])
就完美地搞定了,是多么地流畅,多么地自然,我就喜欢上了这门语言~
我们现在已经在逐步把很多题目翻译成中文了,所以,大家有空就去这里看看吧~最好是大家都能参与到其中来哦~
神一样的Quine
有个很牛B的小日本搞出来的东西。
# ruby l=92.chr;eval s="s=s.dump[r=1..-2].gsub(/("+l*4+"){4,}(?!\")/){|t|'\"+l*%d+\"'%(t .size/2)};5.times{s=s.dump[r]};puts\"# python\\nprint(\\\"# perl\\\\nprint(\\\\\\ \"# lua"+l*4+"nprint("+l*7+"\"(* ocaml *)"+l*8+"nprint_endline"+l*15+"\"-- haskel l"+l*16+"nimport Data.List;import Data.Bits;import Data.Char;main=putStrLn("+l*31 +"\"/* C */"+l*32+"n#include<stdio.h>"+l*32+"nint main(void){char*s[501]={"+l*31+ "\"++intercalate"+l*31+"\","+l*31+"\"(c(tail(init(show("+l*31+"\"/* Java */"+l*32 +"npublic class QuineRelay{public static void main(String[]a){String[]s={"+l*31+" \"++intercalate"+l*31+"\","+l*31+"\"(c("+l*31+"\"brainfuck"+l*64+"n++++++++[>++++ <-]+++++++++>>++++++++++"+l*31+"\"++(concat(snd(mapAccumL h 2("+l*31+"\"110"+l*31 +"\"++g(length s)++"+l*31+"\"22111211100111112021111102011112120012"+l*31+"\"++co ncatMap("+l*32+"c->let d=ord c in if d<11then"+l*31+"\"21002"+l*31+"\"else"+l*31+ "\"111"+l*31+"\"++g d++"+l*31+"\"22102"+l*31+"\")s++"+l*31+"\"2100211101012021122 2211211101000120211021120221102111000110120211202"+l*31+"\"))))))++"+l*31+"\","+l *63+"\""+l*64+"n"+l*63+"\"};int i=0;for(;i<94;i++)System.out.print(s[i]);}}"+l*31 +"\")))))++"+l*31+"\",0};int i=0;for(;s[i];i++)printf("+l*63+"\"%s"+l*63+"\",s[i] );puts("+l*63+"\""+l*63+"\");return 0;}"+l*31+"\");c s=map("+l*32+"s->"+l*31+"\"" +l*63+"\""+l*31+"\"++s++"+l*31+"\""+l*63+"\""+l*31+"\")(unfoldr t s);t[]=Nothing; t s=Just(splitAt(if length s>w&&s!!w=='"+l*31+"\"'then 501else w)s);w=500;f 0=Not hing;f x=Just((if x`mod`2>0then '0'else '1'),x`div`2);g x= reverse (unfoldr f x); h p c=let d=ord c-48in(d,replicate(abs(p-d))(if d<p then '<'else '>')++"+l*31+"\" ."+l*31+"\");s="+l*31+"\"# ruby"+l*32+"n"+l*31+"\"++"+l*31+"\"l=92.chr;eval s=\"+ (z=l*31)+\"\\\"\"+s+z+\"\\\""+l*31+"\"++"+l*31+"\""+l*32+"n"+l*31+"\""+l*15+"\""+ l*7+"\")"+l*4+"n\\\\\\\")\\\")\"########### (c) Yusuke Endoh, 2009 ###########\n"
这段ruby代码,相当牛,如作者所说,运行这段ruby,生成一段python代码,再运行python代码,生成一段perl代码,再运行perl代码,生成一段lua代码。。。这样一直下去,经过11种语言,最后。。。居然又能重新得到之前的ruby代码。。
这11种语言是:ruby 1.8.7-p72、Python 2.5.2、perl v5.10.0、Lua 5.0.3、OCaml 3.10.2、ghc-6.8.2、gcc 4.3.2、java “1.5.0_17″、beef 0.0.6-2、whitespace 0.3-2、unlambda 2.0.0-5。
在est这里看到了介绍,实在忍不住,把所有解释器都装上验证了一把,果然是可以的。彻底无语了,特此把中间结果都打包放上来,供大家瞻仰。
ubuntu下也想自己试试的话,得确保有这些包: ruby lunar lua50 ocaml-interp ghc6 sun-java5-jdk beef whitespace unlambda
PS: 我以为 brainfuck 就已经很BT了,没想到还有更BT的 whitespace ,彻底无语了。
Bash其实也可以做CGI用
标题其实是“废话”。因为,其实稍微熟悉web原理的都知道,理论上,所有可执行的程序/脚本,都可以被server程序(例如apache/mini_httpd/lighttpd/nginx等)调用,只要能够输出HTML,都可以成功。
而这个用bash做CGI的想法,纯属闲着无聊的时候,瞎想出来的。不过有这个想法的,我肯定不是第一人,这里和这里都有类似的描述。
不过,我这个Web From Scratch的过程还颇有点波折,试了蛮久才成功,就在此记录一下。
其实,说白了都是也就一句话:扩展名不能随意取。当然这个只是针对我这个主机的apache来说的,其他的server可能有其他的规则,暂且不做定论。
之前我一直把我的脚本文件名写成index.sh,结果怎么试都不行,后来无意中改成inedx.py(虽然里面还是#!/bin/bash开头的)居然就可以了,于是我就找到原因了,现在我改成个更通用的index.cgi了,哈哈。
另外关于.htaccess,由于自己也是一知半解,就不讨论了,有兴趣的话,可以看看这里,这里只贴下我用到的代码,可以把对此域名的任何路径的请求都让index.cgi来处理。
RewriteEngine on
DirectoryIndex index.cgi
RewriteCond %{REQUEST_URI} !(index.cgi)
RewriteRule ^(.*)$ index.cgi/$1 [L]来看看我的bash,就是简单地输出服务器信息:
#!/bin/bash #下面这两行头一定要有,不然可是会引发 500 Internal Server Error 错误的。 echo "Content-type: text/html" echo "" echo "<h1>Bash CGI works!</h1>" env | while read line;do echo "<b>" echo "$line" | cut -d= -f 1 echo "</b>=<i>" echo "$line" | cut -d= -f 2- echo "</i><br>" done
最近几天,可以点击 http://hzlug.org/abc?xxx=yyy 观察这个脚本运行的效果,以后可以把这个地址做它用,嘿嘿。
可以看到 REDIRECT_URL 和 QUERY_STRING 这两个环境变量分别是路径和参数,这样理论上就可以用一个脚本来完成很复杂的功能了~
至于HZLUG到底会做成什么样子,还请大家多多提意见哦~
用python来收发邮件
由于python的模块很强大,用python来收发邮件,就显得很轻松了。
python不仅有email模块,还有专门处理pop、smtp甚至imap的模块。
下面就来演示一下这几个的用法,先看看怎么用pop3和email模块来收邮件。
>>> import poplib >>> p=poplib.POP3_SSL('pop.gmail.com') #如果服务器不需要启用SSL,那么只需要用 poplib.POP3('xxx.com') 就好了。 >>> p.user('linuxcn.ibot') '+OK send PASS' >>> p.pass_('密码') '+OK Welcome.' >>> p.stat() #统计状态,返回一个元组,第一个表示几封邮件,第二个表示一共几个字节 (2, 4543) >>> p.list() #返回每个邮件的状态 ('+OK 2 messages (4543 bytes)', ['1 3679', '2 864'], 15) >>> p.retr(2) #获取某个邮件的全文,这个邮件就是我自己给另一个测试账号发的邮件,元组里包含了邮件头和邮件的正文。 ('+OK message follows', ['Delivere ...为了排版方便,此处有删节... e--'], 869) >>> mailsrc='\n'.join([l for l in p.retr(2)[1]]) >>> print mailsrc #如果上面还看不出啥的话,这样看应该就明显了。 Delivered-To: linuxcn.ibot@gmail.com Received: by 10.216.47.83 with SMTP id s61cs422102web; Sat, 15 Aug 2009 07:58:32 -0700 (PDT) MIME-Version: 1.0 Received: by 10.114.180.16 with SMTP id c16mr2819847waf.57.1250348310512; Sat, 15 Aug 2009 07:58:30 -0700 (PDT) Date: Sat, 15 Aug 2009 22:58:30 +0800 Message-ID: <ae14629e0908150758n49649527xf326b8c1a60f36bf@mail.gmail.com> Subject: =?UTF-8?B?5rWL6K+V5Li76aKY?= From: LLY <bones7456@gmail.com> To: linuxcn.ibot@gmail.com Content-Type: multipart/alternative; boundary=001636417e2fe4c3a904712f669e --001636417e2fe4c3a904712f669e Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: base64 5rWL6K+V5q2j5paHCg== --001636417e2fe4c3a904712f669e Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: base64 5rWL6K+V5q2j5paHPGJyPgo= --001636417e2fe4c3a904712f669e-- >>> p.quit() #收完邮件了,理论上是要退出一下的 '+OK Farewell.' >>> import email #源码得到了,现在轮到email模块登场了 >>> e=email.message_from_string(mailsrc) #这个就可以把邮件源码转换成一个email的对象了。 >>> print e['subject'] #这个是编码后的主题 =?UTF-8?B?5rWL6K+V5Li76aKY?= >>> print email.header.decode_header(e['subject'])[0][0] #这个是解码后的主题 测试主题 >>> e.get_payload() #获取当前email的有效部分,可以看到有这个邮件有两个部分,从上面的邮件源码,我们也可以得知,此邮件确实有text/plain 和 text/html 两部分 [<email.message.Message instance at 0xb751102c>, <email.message.Message instance at 0xb751172c>] >>> e.get_payload(0) #获取有效部分的第一个,这个还是一个email对象的实例。 <email.message.Message instance at 0xb751102c> >>> type(e) <type 'instance'> >>> type(e.get_payload(0)) <type 'instance'> >>> import base64 #解码邮件正文还得用上base64模块 >>> print base64.decodestring(e.get_payload(0).get_payload()) #解码正文的第一部分 测试正文 >>> print base64.decodestring(e.get_payload(1).get_payload()) #解码正文的第二部分,是html,看来只多了个br而已,哈哈 测试正文<br>
当然,上面的例子只是最简单的,复杂的附件什么的,也可以用库里的相关函数一一搞定的。另外,看文档的意思,传了get_payload的第二个参数按理应该能自动调用base64模块解码的,但是不知道为什么,我没有试验成功,只能自己手工解了~
下面,再来看看怎么用smtp发邮件,如果是复杂的邮件,也需要建立一个email对象的实例,把正文/附件等一一放上去就好,但是作为演示,我们就用邮件的源码来发一个纯手工的,哈哈
>>> import smtplib #加载模块 >>> msg='To: linuxcn.ibot@gmail.com\r\nFrom: my@localhost\r\nSubject: test\r\n\r\nthis is msg body\r\n' #邮件的源码 >>> s=smtplib.SMTP('smtp.163.com') #同样这里也有SMTP_SSL,到底用什么要看服务器的设置 >>> s.login('bones7456','密码') #一般都要登录了,才能发邮件,login里提供两个参数,用户名和密码 (235, 'Authentication successful') >>> s.sendmail('bones7456@163.com','linuxcn.ibot@gmail.com',msg) #发送邮件,三个参数分别是 from/to/msg,就这名简单就成功了。。 {} >>> s.quit() (421, 'closing transmission channel')
就这么几行,一封邮件就发出去了,够简单吧。。。更详细的内容就看官方文档吧~
JSON数据格式简介
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition – December 1999的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。这些特性使JSON成为理想的数据交换语言。
以上摘自JSON官方介绍,这个格式是如此地简单,以至于光看这篇官方文档就可以完全掌握了,而无须其他过多地介绍了。
最初看到这个JSON,是在twitter上,这种小交互量的场景很适合用JSON,比XML更轻巧些。今天,看到新闻,taobao也搞了个开放平台,里面也支持JSON和xml这两种格式,所以我觉得这个格式以后会越来越流行,特发此文关注下。
折腾py2exe
序: 恩,这个确实挺折腾的,几乎一个下午都在搞py2exe,加上晚上又搞了一会儿,总算勉强让gmbox的exe可执行文件运行起来了…
首先,为什么要折腾py2exe呢? 其实就是为了那个gmbox,在设计之初,我就让它打算跨平台支持windows的.为此我也折腾过windows的python运行环境.但是如果那样的话,有windows的朋友要用gmbox,就必须安装python、GTK+库、PyCairo、PyGObject和PyGTK,这可不是一般的烦.所以有市场就会有需求,像我这样的问题我肯定不是第一个遇到的.于是就有了py2exe.
py2exe实际上是python distutils的一个扩展,使用py2exe,你必需有一个windows的环境,安装了python和你程序用到的依赖包(例如gmbox的pygtk等),也就是说,在这个”开发环境”你要能够运行起你的程序,然后下载py2exe,安装到python的lib目录下,就可以用来生成目标exe文件了,以后你只要把生成的东西复制到其他windows的机器,就可以脱离python运行环境和库的依赖了.是不是很爽呢?
虽说网上都说py2exe用起来很简单,但是我还是折腾了不少时间,可能是因为gmbox比较特殊:同时有CLI和GUI,有图标和数据文件,有自己的lib库等,当然更可能是因为我太菜了…嘿嘿..
不管怎么说,在这里记一下折腾的步骤,也许可以让后人少走点弯路:
- 打包文件(gmbox的打包文件在这里,建议边参考代码,边看下面的内容)最好要和你的主程序文件放在同一目录下.我曾经试着把打包文件放在上级目录,结果在搜索依赖库的时候遇到了很多麻烦.
- 打包文件本身其实也是一个python的程序,虽然一般只有一个setup函数.此函数可以有 name,description,version,console,windows,options,data_files 等参数.
- 要生成一个或多个命令行的exe,setup需要一个List型的名为console参数,指名源py文件.
- 要生成一个或多个GUI的exe,setup需要一个List型的名为windows参数,指名源py文件.List的每项都可以有图标等选项,就是icon_resources哪里,图标也是个Tuple的List,但是windows一般只会显示出第一个图标,所以一个就够了.
- 如果你想用png文件直接当图标,那很可能会在生成exe的时候,引起python崩溃,所以还是赶紧转成ico吧
- 如果你和我一样,生成的GUI的exe文件,在执行的时候,报 ImportError: No module named cairo ,那最好在setup函数里加上options,里面有include cairo的选项.
- 如果你也有数据文件(比如glade文件,图片文件等),py2exe默认并不会帮你一起打包,你需要在setup函数中加传data_files参数.data_files需要是一个List,每项可以是直接指向数据文件的字符串,也可以是一个Tuple;如果是前者,数据文件会直接在生成的dist目录下面,如果是后者,Tuple的第一个元素是目标目录,第二个元素是是个源文件名的List,效果是把所有的源文件存放在dist下的指定的目标目录下.(呃,好长好拗口…)
- 在py2exe生成的环境中,__file__这个应用将失效,这个问题的解决方法可以参看这里.个人觉得Alternate Solution更加靠谱.
- 好了,现在如果你已经写好了打包文件(win_packer.py),也对源代码进行了应有的修改,你就可以执行 python win_packer.py py2exe 来生成exe了,执行此命令会在当前目录下多出一个 dist 目录,你只要把dist目录复制出来,运行里面的exe,就可以了
- 最后,如果你的GUI程序还是运行不了,你还需要手工将你的GTK+安装安装目录(默认是C:\GTK)下的etc和lib目录复制到dist目录
当然,由于包含了一堆的运行环境,生成的dist目录将会是比较巨大的,现在的gmbox的exe居然有18M多,嘿嘿,应该还有优化和压缩的空间,改天再研究了~
给python增加IPC模块
前天介绍了linux进程间通信──消息队列,由于消息队列是linux内核提供的功能,所以理所当然地,C语言用起来最为方便:直接include一个sys/msg.h就可以了,所以之前的文章,我也是用C语言来做演示的.
那么我喜欢的Python能不能用IPC呢?能不能像C一样用消息队列呢?
其实,Python的内置模块里,并没有对IPC的支持,但是好在python的可扩展性超强,我们可以用swig来为python增加一个IPC模块.方法如下:
下载这个tar包(修改自这里),解压到任意目录,得到 ipc.h ipc.i Makefile 3个文件,如果你不是用的python2.6,需要修改一下 Makefile 里的路径(python3系列未测试).然后
make && make install
这样,你就可以在python里 import ipc模块了.
还是贴示例代码,保存为ipc_msg.py,并加可执行权限:
#!/usr/bin/env python import sys,ipc if len(sys.argv)==5 and sys.argv[3][0]=='s': ipc_key=int(sys.argv[1]) msg_id = ipc.msgget(ipc_key,0666|ipc.IPC_CREAT) if 0 > msg_id: sys.exit(1) mbuf = ipc.msgbuf() mbuf.mtype = int(sys.argv[2]) mbuf.mtext = sys.argv[4] if 0 > ipc.msgsnd(msg_id,mbuf,len(mbuf.mtext),0): sys.exit(3) print 'Send Success.' elif len(sys.argv)==4 and sys.argv[3][0]=='r': ipc_key=int(sys.argv[1]) mbuf = ipc.msgbuf() msg_id = ipc.msgget(ipc_key,0666) if 0 > msg_id: sys.exit(1) msg_len=ipc.msgrcv(msg_id,mbuf,2048,int(sys.argv[2]),ipc.IPC_NOWAIT) if 0 > msg_len: print 'No message received.' sys.exit(3) else: print 'Recv Success.(%d bytes):'% msg_len print mbuf.mtext elif len(sys.argv)==3 and sys.argv[2][0]=='c': ipc_key=int(sys.argv[1]) id_dsp = ipc.msqid_ds() msg_id = ipc.msgget(ipc_key,0666) if 0 > msg_id: sys.exit(1) if 0 > ipc.msgctl(msg_id,ipc.IPC_RMID,id_dsp): sys.exit(2) else: print "usage: \n%s key type s message --to send message\n\ %s key type r --to receive\n\ %s key c --to clear queue"\ %(sys.argv[0],sys.argv[0],sys.argv[0])
运行结果:
lily@LLY:~/test/ipc$ ipcs -q ------ Message Queues -------- key msqid owner perms used-bytes messages lily@LLY:~/test/ipc$ ./ipc_msg.py 1 2 s abc Send Success. lily@LLY:~/test/ipc$ ipcs -q ------ Message Queues -------- key msqid owner perms used-bytes messages 0x00000001 65536 lily 666 3 1 lily@LLY:~/test/ipc$ ./ipc_msg.py 1 2 r Recv Success.(3 bytes): abc lily@LLY:~/test/ipc$ ipcs -q ------ Message Queues -------- key msqid owner perms used-bytes messages 0x00000001 65536 lily 666 0 0 lily@LLY:~/test/ipc$ ./ipc_msg.py 1 c lily@LLY:~/test/ipc$ ipcs -q ------ Message Queues -------- key msqid owner perms used-bytes messages lily@LLY:~/test/ipc$
怎么样?和之前的C语言版本一模一样吧?
linux进程间通信──消息队列
linux自古以来就是一个多任务多用户的操作系统,所以linux的进程间通信(Inter-Process Communication──IPC)就显得非常重要了。
IPC是一种标准的Unix通讯机制,目前有以下几种通讯方式:管道(Pipe)、信号量(Semaphore)、互斥体(Mutex)、共享内存(Shared Memory)和消息队列(Message Queue),当然也有其他的方式,比如文件系统和dbus等。
今天我就来介绍一种简单实用的进程间通信方式:消息队列(Message Queue)。
首先说说消息队列的优缺点:
1.消息队列只适用于单台主机的进程间通信,如果是不同主机,需要用socket等其他方式,也就不属于IPC的范畴了。
2.消息队列可以实现异步通信,这似乎是优点,但说是它缺点也是可以的:通讯往往不是实时的。
3.消息队列有大小限制,通常只用于小数据量的发送。系统对用户的大小限制可以通过 ulimit -q 命令进行查询。
4.消息队列可以实现阻塞调用和非阻塞调用。
5.实现简单,且可移植性好。
下面通过一个实例来进行说明,以下文件保存成 ipc_msg.c:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/msg.h> int main(int argc, char *argv[]){ int ipc_key,msg_id,msg_len; long mtype; void * mbuf; if(argc==5 && argv[3][0]=='s'){ ipc_key=atoi(argv[1]); mtype=atol(argv[2]); msg_len=strlen(argv[4]); if ( 0>(msg_id=msgget(ipc_key, 0666|IPC_CREAT)))return 1; if ( NULL==(mbuf=malloc(msg_len+sizeof(long)+1)) )return 2; memcpy(mbuf, (void *)&mtype, sizeof(long) ); memcpy(mbuf+sizeof(long), (void *)argv[4], msg_len ); if ( 0>msgsnd(msg_id, (struct msgbuf *)mbuf, msg_len, 0) )return 3; printf("Send Success.n"); }else if(argc==4 && argv[3][0]=='r'){ ipc_key=atoi(argv[1]); mtype=atol(argv[2]); if ( 0>(msg_id=msgget(ipc_key, 0666)))return 1; if ( NULL==(mbuf=malloc(4096)) )return 2; if ( 0>(msg_len=msgrcv(msg_id,(struct msgbuf *)mbuf, 4000, mtype, IPC_NOWAIT))){ printf("No message received.n"); return 3; } printf("Recv Success.(%d bytes):n",msg_len); printf("%sn",(char *)(mbuf+sizeof(long))); }else if(argc==3 && argv[2][0]=='c'){ ipc_key=atoi(argv[1]); if ( 0>(msg_id=msgget(ipc_key, 0666)))return 1; if ( 0>msgctl(msg_id,IPC_RMID,(struct msqid_ds *)mbuf) )return 2; }else{ printf("usage:" "%s key type s message --to send messagen" "%s key type r --to receiven" "%s key c --to clear queuen" ,argv[0],argv[0],argv[0]); } return 0; }
以上程序,实现了发数据到消息队列和从消息队列收取数据的功能。
第一个参数需要是一个整形数值,表示消息队列的Key;
第二个参数是一个长整形的数值,表示消息的Type,Key+Type 可以唯一确定一个先进先出的消息队列。
第三个参数如果是‘s’则把第四个参数发到指定消息队列,如果是‘r’则从指定消息队列收取消息,并打印。
另外,如果第二个参数是‘c’,则把Key对应的队列删除。
让我们来运行一下试试:
$ gcc -o ipc_msg ipc_msg.c #编译 $ ipcs -q ------ Message Queues -------- key msqid owner perms used-bytes messages #一开始系统中没有消息队列。 $ ./ipc_msg 1 2 s abc Send Success. #发送了一个内容为abc的消息 $ ipcs -q ------ Message Queues -------- key msqid owner perms used-bytes messages 0x00000001 262144 lily 666 3 1 #发送了一个消息以后,队列里有消息了,key是1,有3个字节。 $ ./ipc_msg 1 2 r Recv Success.(3 bytes): abc #从消息队列成功收到消息了。 $ ipcs -q ------ Message Queues -------- key msqid owner perms used-bytes messages 0x00000001 262144 lily 666 0 0 #收完以后,空的消息队列仍然存在,不会自动消失。 $ ./ipc_msg 1 c #删除队列 $ ipcs -q ------ Message Queues -------- key msqid owner perms used-bytes messages #成功删除了,回到原始状态。
本文以GNU自由文档许可证发表.
python用着太顺手了
(此文纯属自言自语,基本可以忽略,呵呵.)
python用着太顺手了,其实是很久以前就有这种感觉,最近印象比较深的一次就是在做Project Euler的第一题的时候,那题比较简单,要求1000以内所有能被3或5整除的自然数之和.这题其实用什么语言都不复杂,但是用python的话,只需要一行:
sum([n for n in range(1000) if n%3==0 or n%5==0])
接近自然语言的表达看起来好舒服,而且也相当简洁.
然后今天,我又更新了一下gmbox,基本上把CLI重新写了一遍,又有同样的感觉了.gmbox的命令行,分交互式和非交互式两种,刚好用cmd和optparse两个内置模块轻松搞定.而且cmd模块支持欢迎界面/自定义提示符/readline库;optparse支持长短选项和混杂无序的选项,并自动生成帮助界面.真是太爽了.这两种模式加起来才140行左右的代码.去掉文件头,只有120行…
以后继续学习python.哈…
bones7456 WP theme 微调
看到Matrix 67的blog的主题,觉得有一点很不错:就是右侧的最新评论那里,一开始是每个评论只占据一行的位置,只有在鼠标放上去的时候,才会把内容展开.
这样的好处很明显:平时节省页面空间,布局也更漂亮,鼠标放上去的时候显示出该有的信息,也不影响使用.
于是,有样学样,把这一小细节学习了过来(呃..好吧,其实就是抄了过来…).
在实现上,没去动WP带的dynamic_sidebar函数,而是偷懒了一下,在页面基本展开完以后,用js处理了一下style,并添加事件函数.看现在是不是更好看了?
之前我都只敢放5个最新评论,因为再多,就不美观了.现在放10个也不是问题.
如果你也喜欢并想试试本WP主题,可以到这里下载最新的代码.
:-)