用Python Descriptor弱智了一把

Python Descriptor是个有意思的功能,类似于c++里面的重载operator=和operator T,可以在你访问这个对象的时候,调你定义的__get__(),把返回值作为访问结果,在你给对象赋值的时候,调你的__set__()。 昨晚大约是在搞这么一个类: class Field(object): def __get__(self, obj, objtype): …. def __set__(self, obj, val): ….   class Data: x = Field()   d = Data()class Field(object): def __get__(self, obj, objtype): …. def __set__(self, obj, val): …. class Data: x = Field() d = Data() 然后在访问d.x的时候,没啥问题,__get__被调用了;但是给d.x赋值的时候,__set__没被调用,只是貌似给d搞上了一个域叫x,之后再访问d.x也不会调__get__了…… 在折腾了若干时间之后,最后发现问题特别弱智:Data不是new-style class。只要改成Data(object)就好了……   虽然是我弱智吧,这个语言方面也有问题吧…… 既然old-style class不支持Descriptor,为啥__get__能用__set__却不行…… 而且也没个警告之类……

正则表达式与有一定格式的文本

最近用aMule扒下来一堆cd。这些cd很神奇,是一堆iso,里面是一些flac文件…… 这些flac都没有歌曲信息,于是我想办法提取歌曲信息存进去…… 首先是文件名。文件名还算有点规律,都是###-(#) xxx _ xxx _ xxx _ xxx这样的。但是搞了没几张就发现,这个不太靠谱。首先是,有时候分隔用的是_,有时候是__…… 其次有时候一个域内部也会有_,例如标题里面时常出现…… 再次,看上去不少文件名最后被截断了…… 于是为了搞出靠谱的歌曲信息,还是用别的办法。 其次,每个cd还有个Vol ## xxx.txt的文件。打开一看,好歹比文件名有规律一点,第一行是专辑信息,之后有些# xxx : xxx / xxx = xxx这样的行,最后还有一些#-# xxx的表示录音时间的行。于是搞了个简单的python脚本,parse这些信息存进去…… 既然是parse文本,那就正则表达式。一开始可简单了。再配合glob找文件,mutagen保存歌曲信息,看上去都很美好…… 直到处理没几张专辑之后我发现:格式貌似不止一种…… 接下来就是各种麻烦的事情…… 有时候,因为是一个作品的各个部分,除了第一部分那行外艺术家之类信息统统没有,只有一个小标题…… 有时候,艺术家信息在下面录音时间那行的末尾…… 有时候,录音时间那些行不是#-#或者#,而是#、#-#、#-#这样…… 有时候,xxx : xxx表示作曲:标题,但有时候,xxx : xxx表示大标题:小标题…… 还有时候,xxx : xxx就完全是个小标题…… 有时候,大标题和小标题之间用—分隔,但有时候,用:分隔…… 有时候,:变成了;…… 有时候,/不见了…… 反正一开始一个没几行的python脚本膨胀到了超过两百行,有时候还需要手动处理…… 例如有一张里面艺术家跑到了第一行专辑信息里…… 最后好歹算是差不多弄完了。虽说这还是有点格式的文本(我觉得肯定是人写的),正则表达式处理还是很麻烦。如果处理系统有音乐相关信息的话,估计能够更好地完成任务(例如知道作曲家都有那些这样)……

忘了重定向stderr导致的某问题

最近某python程序常常抛exception。而且比较神奇的是,貌似这个exception是一层层抛出来的。 先是最内层except块打的log,然后是次外层,然后是再外面…… 我本来写的代码并不会重抛异常,所以这很神奇…… except块大约是这样的: except Exception as e: Log.error("send error: %r" % e) traceback.print_exc()except Exception as e: Log.error("send error: %r" % e) traceback.print_exc() 能看见第一行的log,但是之后print_exc()的结果就没了。下一行log是更外面的except块的log…… 于是这个大概就是print_exc()抛的异常,但是这个东西能抛啥…… 之后想了一下,就算是异常一路抛到最外面,也应该有个backtrace,而log里啥都没有…… 想想backtrace是打到stderr的,难道stderr没有重定向…… 之后再看了一眼,log是打到stdout的…… 再去看启动python程序的脚本,貌似只重定向了stdout,忘了重定向stderr了…… 难道断了的stderr不能写?我又写了个小程序ssh到服务器上跑: #!/usr/bin/env python   import sys import time   time.sleep(10)   try: sys.stderr.write(’test\n’) except Exception as e: print "Exception: %r" % e#!/usr/bin/env python import sys import …

Continue reading ‘忘了重定向stderr导致的某问题’ »

折腾

折腾了几天,搞了各种事情* 升级Avant Window Navigator到trunk(0.3.9)有一大堆的事情,比如说:# bzr up之后,有冲突,干脆全部干掉重来。发现configure有问题,引用了莫名其妙的ac_python_version变量,这个东西哪里都没有。只好手动改成2.6。# 引用了libdesktop-agnostic,ports里没有,上网去发现貌似也在launchpad上边,可能也是awn这群人搞的,遂bzr co下来# 结果编译的时候有诸多问题,上网去,发现有bug-report,说是vala版本太新,而且他还branch了一个various-fixes分支出来# 第一次听说vala,貌似是利用gobject这套系统,配合一个类似于C#的语言,给C以面向对象能力。编译的时候先弄成C再编译# 再bzr co了那个fixes branch,终于好了。回头对付awn,还算比较容易# 新版多了个curve模式,貌似速度也好不少,稳定性也是,看来这个rewrite还不错* 升级awn-extras也有不少事情:# 发现里面的各个菜单组件都或者崩溃或者没有程序菜单,追溯到python-gmenu,最后看调试信息,发现没有applications.menu文件# 本来想生成一个完了,但是下了个菜单编辑工具alacarte,发现这个里面已经有程序菜单了…… 而且gnome-panel也有…… 标准不统一啊……# 之后再查资料,发现说XDG这套标准允许有前缀,并且通过locate得知有一个gnome-applications.menu在恰当的地方# 最后通过把XDG_MENU_PREFIX设为gnome-解决# 之后又是发现那个Media Player Applet不能放大的(不是文件大小)视频。怀疑和之前totem的问题一样# 看代码发现用的playbin这个gstreamer组件,直接gst-launch,果然出错,而且信息和totem的一样# 上网搜了一下,有人说totem的pkg-message里说了这个问题,果然有…… 用了就好了# 说明这个问题不只totem有,用gstreamer的都有…… 为啥默认的那些shm的参数那么小……* xps文件查看上两天有人发来xps文件,不能看…… 去网上下了XPS Essentials装,结果wine运行说有gdiplus的函数没实现…… 搜了之后,发现新版wine实现了,遂下载新版,结果换了一个函数…… 只好拷了一个gdiplus.dll过来,运行倒是可以,就是换页要好几秒……于是去网上找开源解决方案,找到ghostxps,后来发现就是ghostscript那个公司做的。直接转pdf,10M的xps变成了5xxK,但是里面图片质量很差。去网上看了一下,对latex转pdf有人说应该先转ps再ps2pdf,应该是同理。但是直接转出来的ps竟然有4xxM…… 再转pdf,有17M,还能忍受,质量很好* skypebsd ports里面那个skype是static的2.0.0.72-oss版,我输入不了中文,遂尝试新版。结果新版2.1.0.xx的dynamic版都会卡死在futex系统调用上,而static版不但不能输入中文,还没有声音……搜索得知,新版用了pulse,遂用rpm安装alsa的pulse插件,linux的pulse库等,结果运行时说shm_open没有实现…… 还是不行又尝试装了alsa的oss插件,并且设为默认,这次终于有声音了,但是…… 不能录音……最后还是回归老的了……* 自动挂载本来我山寨了一个自动挂载脚本,利用devd的CDEV建立事件,在ntfs/*和msdosfs/*出现的时候,自动挂载到/mnt/*结果现在有了iPod,就有问题了:我一般只是想充电而已于是要挂载自动camcontrol eject,问题是CDEV事件不包括设备名,只有label。在找不到反查工具的情况下,只好自己从label查设备大致上就是一个枚举,利用gpart结果得到所有设备,然后用glabel得到上面的label,并且进行匹配,符合的就是对应设备。搞的时候发现,glabel status的第一行输出一直是Name Status Components,而Name下面显示的就是label,而且Name的最后一个字母严格和label最后一个字母对齐,通过这个,可以保证从输出结果得到的label是完整的label,不多不少。现在碰见iPod就会自动卸载了,真不错……* easytag的崩溃问题本来easytag给某些歌写tag的时候,总是崩溃。这两天研究一下,发现都是不正常的ape tag引起的。虽然easytag本身只写id3 tag,但是他写的时候,会先清除ape tag,而要清除就要先解释,于是就挂了…… 我搞了py-apetag下来,结果删tag的时候也说不能解释……你们删除tag就不会简单地先删掉再建一个空的么…… 非要解释……最后手动把文件结尾APETAGEX开始的东西全干掉,世界清静了…… 感想:# gstreamer好强大,我视频库里那些视频都可以放…… 虽然对字幕的支持还是令人怀疑# 发现一个好东西,gst-editor,类似于windows里directx开发包里那个编辑directshow filter图的那个东西,这里是编辑gstreamer …

Continue reading ‘折腾’ »

英语46级查分的程序

昨天46级能够查分了,研究了一下…… 主页面调用了一段javascript,验证码竟然是本地验证的…… 这个不说,其实最后查分就是通过XMLHttpRequest直接查…… 就没什么加密一类的事情…… 之后找了一下,好像XMLHttpRequest这个东西还只有Javascript里面才有,python用起来还不方便…… 用FireBug试了一下,因为这个查分系统的请求里面没有数据,所以这个请求其实很简单,拿urllib糊弄一下就好了…… 另外关于FireFox里面不能查的问题,貌似是FireFox的XMLHttpRequest在send(null)的时候HTTP头里面没有Content Length字段,其实send(“”)就可以了…… 另外,最后这个系统还检查一下Referer,至少不是什么都不干……  1 import urllib  2 import urllib2  3  4 id = “Your ID“  5 t = “4“  6 url = ‘http://cet.99sushe.com/cetscore_99sushe0902.html?t=‘ + t + ‘&id=‘ + id  7 values = {}  8 headers = { “Referer“ : “http://cet.99sushe.com“ }  9 10 data = urllib.urlencode(values) 11 req = urllib2.Request(url, data, headers) 12 response = …

Continue reading ‘英语46级查分的程序’ »

博客转移记(1)——关于metaWeblog接口

本来想直接用网上的博客转移服务,无奈找了好几个,比如http://blogmover.redv.com,但是这家的Blogger写入插件好像坏了…… 又如maikr,这个要注册,而且还是windows程序…… 最后只好自己写一个,就当练练Python。 首先是读取原mblogger.cn上的。这个支持metaWeblog接口,试了一下,非常好用。基于Python这种脚本语言的灵活性,对象的方法能够动态生成(估计差不多就像perl里面有个函数能处理未定义的方法调用一样……),metaWeblog的接口直接就成了Python里面对象的方法。 首先,引用xmlrpclib,这个东西现在Python自带了。 接下来 server_uri = “http://computer.mblogger.cn/henryhu/services/metablogapi.aspx” sp = xmlrpclib.ServerProxy(server_uri) 这样就搞出来一个能够帮你进行xmlrpc调用的对象了。它有.system.listMethods()方法,还有.system.methodHelp(method)方法,不但能知道有哪些方法,还有使用说明…… 这个实在是很好用…… 随后 blogs = sp.blogger.getUsersBlogs(progname, username, password) 得到一个list,里面每个对象是个dict,就是一个blog。 这个dict里面的blogid,之后就用来代表这个blog了。blogName对应的博客标题。 for post in sp.metaWeblog.getRecentPosts(blogid, username, password, POST_LIMIT): 这个是metaWeblog的方法,获取最近的POST_LIMIT个帖子。自然你希望获取全部的话,取个什么99999之类的就行了…… 这个post就是个dict,里面有title(标题),description(内容),link(帖子链接),dateCreated(写作日期),categories(分类)。 前三个都是字符串。第三个就复杂点。 返回的这个格式,应该是XMLRPC的标准格式,但是Blogger不认,Blogger认datetime对象的isoformat()返回的格式。 datetime.datetime.strptime(post[‘dateCreated’].value,”%Y%m%dT%H:%M:%S”)+datetime.timedelta(hours=-8) 这样能够把它转换成datetime对象。之所以要后面减掉8小时,因为这里返回的是本地时间(UTC+8),而Blogger需要的是UTC时间,所以要-8。 categories是个list,每项是个字符串,就是分类。 后来搞了一天不成,第二天想着把Comments也移过来。 这个不是metaWeblog力所能及的了,只好直接抓网页了。 本来想把comment的内容提取出来用Blogger API的comment功能发上去。无奈这个comment功能目前只能用自己的帐号发comment,这个看上去就很不好看。后来想想,干脆直接把网页的评论部分处理一下,附在内容后面,还能保存原有风格,以及发送时间、发送人信息等。 httpold = urllib2.urlopen(post[‘link’]).read() 这样先把网页抓下来。 草稿也是返回的,而草稿会抓来一个错误网页。另一方面,在抓下来的网页中发现错误,我就认为这个是草稿——虽然这个像dirty hack,但是也能用用~ commentpart = comm_exp.search(httpold).groups()[0] newcommentpart = comm_re2.subn(“”,commentpart) 其中 comm_exp = …

Continue reading ‘博客转移记(1)——关于metaWeblog接口’ »

技术blog搬家

其实我有一个技术blog,但是没什么人去……原来架在mblogger.cn上,但是这个地方越来越缺乏管理,用户流失严重,就是懒得搬。话说这个也是我一开始写的blog。这个地方基于.Text平台,提供metaWeblog接口。我打算搬到blogger。在网上找了一下,有现成的博客搬家的地方。但是试了一下,都不能用……比如说,http://blogmover.redv.com/,这个地方能够读出原来的blog,但是写到blogger的模块出问题了……又如maikr,需要登录才能用,而网站挂了,于是注册不了……最后只好自己写一个搬家程序了……既然近期学习python,那么练一下也好。python自带xmlrpclib模块,能够和metaWeblog通讯。尝试了一下,metaWeblog的接口还真好用,不一会儿就能够读出blog了。话说python生产力就是高阿,随便弄一下就好了,有什么问题搜一下也能很快解决。如果…… 如果python不是用空格/缩进表示层次的话,那就更好了!然后去研究写到blogger的方法。这时候我发现,虽然metaWeblog基于blogger API,但是那是老的blogger API……新的Blogger被Google整合到了GData API框架里面,于是巨麻烦无比……Google的人们是不是太聪明了…… 总是觉得自己发明的东西比较好,不用现成的…… 然后弄出麻烦的东西,光了解就要不少时间……还好有python的gdata库,自带了访问blogger服务的样例。但是又有一个问题:貌似Blogger的GData访问方法被GFW掉了……只好改了,用SSL,又耗掉一堆时间……最后,折腾了一大堆,终于是把这个搬家程序写出来了……但是,最后用的时候碰见问题了: status 400Blog has exceeded rate limit or otherwise requires word verificationfor new posts COW! 这可怎么搬家啊……