麦田守望者's profile异想空间PhotosBlogLists Tools Help

Blog


    4/17/2008

    解决django 0.96版本与PostgreSQL 8.3.1不兼容的问题

    在Windows环境中,使用django(0.96版本)、PostgreSQL(8.3.1版本),和psycopg2库开发Web应用需要先解决一个小问题。我们需要自己手动修改django的一行代码。代码位于如下文件中,假设Python安装在C盘python25目录中:

    c:\python25\Lib\site-packages\django\db\backends\postgresql_psycopg2\base.py

    57行,源代码:

    postgres_version = [int(val) for val in cursor.fetchone()[0].split()[1].split('.')]

    修改后的代码:

    postgres_version = [int(val[0]) for val in cursor.fetchone()[0].split()[1].split('.')]

    造成这个不兼容问题的原因是,从8.3版本开始Windows版本的PostgreSQL使用Visual C++编译,导致version函数的返回值较之8.2系列的version函数有很大不同。因此,django从version函数返回值中解析PostgreSQL的版本号时就出现了错误。

    3/4/2008

    在psycopg2和MySQLdb中处理中文

    在psycopg2和MySQLdb中能够很好的处理中文。
    先说psycopg2:
    首先,PostgreSQL服务器端应该使用UTF-8编码;接下来,在connect服务器之后,在SELECT任何数据之前,先执行命令:
      SET CLIENT_ENCODING TO gbk
    然后,可以执行SELECT读取数据。psycopg2以字节串的形式返回包含中文的字符串。
    再说MySQLdb:
    在创建到MySQL的连接对象的时候,给MySQLdb的connect方法传入charset参数:
      cn = MySQLdb.connect(db='mydb', host='localhost', user='root', passwd='mypassword', charset='gbk')
    MySQLdb以Unicode字符串对象返回包含中文的字符串。
    运行环境:Python 2.4.4
    9/26/2006

    DB-API 2.0 应用心得一小则

    近日在尝试Python 2.5的sqlite3模块的时候,发现在关闭cursor和connection对象后,任何insert的数据根本无法保存进sqlite数据库。后来经limodou指点和再次翻看DB-API 2.0规范后得知,事情的真相是这样的。
     
    INSERT的数据不会立即写入到数据库中。我们可以将这理解成缓存机制或者事务机制,调用Connection对象的commit方法后,数据才实实在在的写入数据库的物理文件中。当我们调用Connection对象的close方法关闭到数据库的连接的时候,它会隐式地rollback所有未被commit的操作。所以这就是我为什么遇到上述问题的所在,在关闭数据库连接之前,没有调用Connection对象的commit方法。
     
    在此感谢limodou的帮助!
    9/7/2006

    IronPython 1.0 released

    IronPython 1.0发布了,趁着间歇的功夫看了看Tutorial。让我感到兴奋的一点是IronPython不仅能够无缝的访问.NET的整个类库,而且通过简单的设置还能够访问Python的标准类库。但是,实做之后却发现import成功了,某些类的方法调用却失败了,而某些类能够正常使用。现在还不清楚是什么原因。有待与大家的交流和进一步学习。
     
    IronPython对游走在Python和.NET之间的人来说,意味着什么呢?用简单而强大的Python可以操控.NET、Python标准类库、不需要而外的支持即可访问COM组件,而且可以利用Visual Studio 2005编写和调试。哇哦,开动脑筋吧!
    9/3/2006

    对Python字符编码的又一点补充,我想这可以是进一步完善的方面

    无论Python字符编码函数的什么应用方式,它们都是针对一个字符串,而且这个字符串中的所有字符都可以被编码或者解码。现在有这样一种应用场景,接收到一段数据,数据中包括的是以utf-8格式编码的字符,我们需要将这些字符解码以便看到它们本来的文字。直接使用utf-8的decode函数吗,大多数情况下decode都会返回期望的结果,但是有的时候也会不如人意。为什么,是不是我们忽略了什么?想一想,是的。如果我们获得的数据只包括了encode结果的一部分,那么decode当然会失败,因为没有提供完整的解码信息。
     
    解决这个问题,在.NET中是这样做的。Decoder类负责对字节序列解码。Decoder对象会尽可能多的对字节序列执行解码,并且缓存末尾可能出现的不完整的解码字节序列。这些字节会参与到下一次的解码操作中。这种解决办法尤其适用于对网络数据交换和文件内容的处理,而且能够便于开发人员优化程序的内存使用率。
    显然,codecs模块中的一个单一decode函数行为,并不能够提供上述同等的功能。
     
    为了能够在Python中实现对连续字节块的解码,我模仿.NET的办法,基于UnicodeDecodeError异常消息编写了一个Decoder类。尽管能够达到目标,但还是有几点值得注意。
    • 每次都要捕获异常来判断不能完成解码的字节位置会导致性能问题。
    • 对UnicodeDecodeError异常消息的依赖,导致对codecs模块版本的依赖性。如果将来UnicodeDecodeError的异常消息内容发生变化,Decoder可能无法正常工作。
    • 类的正确执行,依赖于使用者在构造函数中传递正确的编码名称。
    此类在Python 2.4.3中运行通过。
    import codecs, re, sys
    class Decoder:
        def __init__(self, encoding):
            self.buf = ""
            self.decode = codecs.getdecoder(encoding)
            self.possible_ore = (re.compile(r".+in position (\d+).+"),
                                 re.compile(r".+in position (\d\-\d+).+"))
    
        def getstring(self, bytestream):
            """Decoding from the bytestream to get unicode string. The bytestream contains raw bytes."""
            self.buf += bytestream
            try:
                unicodestring = self.decode(self.buf)
                self.buf = ""
                return unicodestring[0]
            except UnicodeDecodeError, msg:
                handled_msg = str(msg)
                om = self.possible_ore[0].match(handled_msg)
                if om == None:
                    om = self.possible_ore[1].match(handled_msg)
                    if om == None:
                        print "Decoder class does not support current codecs' edition."
                        sys.exit(1)
                    else:
                        return self.decode("")[0]
                else:
                    pos = int(om.group(1))
                    if pos == len(self.buf) - 1:
                        return self.decode("")[0]
                    else:
                        unicodestring = self.decode(self.buf[0:pos])
                        self.buf = self.buf[pos:]
                        return unicodestring[0]
    
    8/26/2006

    对字符编码函数使用方法的一点补充

    对一个字符串进行字符编码和解码最直接的办法是调用字符串方法decode和encode。两个方法各自只接受一个参数,即字符编码名称。可以这样使用它们:
    >>> s0 = "爱我中华"
    >>> us = s0.decode("gb2312")
    >>> us
    u'\u7231\u6211\u4e2d\u534e'
    >>> s1 = us.encode("gb2312")
    >>> s1
    '\xb0\xae\xce\xd2\xd6\xd0\xbb\xaa'
    >>> s0
    '\xb0\xae\xce\xd2\xd6\xd0\xbb\xaa'
     
    调用字符串的decode和encode方法有一个好处是,不用显式import codecs模块,更不用lookup特定字符编码的decode和encode函数。但是这种方法不适用于对decode和encode方法多次重复调用的场合,主要是从代码的执行效率方面考虑的。
    8/20/2006

    使用codecs模块,在Python中完成字符编码

    字符的编码是按照某种规则在单字节字符和多字节字符之间进行转换的某种方法。从单字节到多字节叫做decoding,从多字节到单字节叫做encoding。在这些规则中经常用到的无非是UTF-8和GB2312两种。
     
    在Python中,codecs模块提供了实现这些规则的方法,通过模块公开的方法我们能够方便地获取某种编码方式的Encoder和Decoder工厂函数(Factory function),以及StreamReader、StreamWriter和StreamReaderWriter类。
     
    使用“import codecs”导入codecs模块。
     
    codecs模块中重要的函数之一是lookup,它只有一个参数encoding,指的是编码方式的名称,即utf-8或者gb2312等等。如下示例:
    >>> import codecs
    >>> t = codecs.lookup("utf-8")
    >>> print t
    (<built-in function utf_8_encode>, <function decode at 0x00AA25B0>, <class encodings.utf_8.StreamReader at 0x00AA0720>, <class encodings.utf_8.StreamWriter at 0x00AA06F0>)
    >>> encoder = t[0]
    >>> decoder = t[1]
    >>> StreamReader = t[2]
    >>> StreamWriter = t[3]
    lookup函数返回一个包含四个元素的TUPLE,其中t[0]是encoder的函数引用,t[1]是decoder的函数引用,t[2]是UTF-8编码方式的StreamReader类对象引用,t[3]是UTF-8编码方式的StreamWriter类对象引用相信对Python熟悉的你肯定知道接下来该怎么用它们了。
     
    codecs模块还提供了方便程序员使用的单独函数,以简化对lookup的调用。它们是:
    • getencoder(encoding)
    • getdecoder(encoding)
    • getreader(encoding)
    • getwriter(encoding)
    如果我们只是想获取一种utf-8编码的encoder方法,那么只需要这样做:
    >>> encoder = codecs.getencoder("utf-8")
     
    另外,对于StreamReader和StreamWriter的简化,codecs模块提供一个open方法。相对于built-in对象File的open方法,前者多了三个参数encoding, errors, buffering。这三个参数都是可选参数,但是对于应用来说,需要明确指定encoding的值,而errors和buffering使用默认值即可。使用方法如下:
    >>> fin = codecs.open("e:\\mycomputer.txt", "r", "utf-8")
    >>> print fin.readline()
    这是我的电脑
    >>> fin.close()
     
    总结一下,codecs模块为我们解决的字符编码的处理提供了lookup方法,它接受一个字符编码名称的参数,并返回指定字符编码对应的encoder、decoder、StreamReader和StreamWriter的函数对象和类对象的引用。为了简化对lookup方法的调用,codecs还提供了getencoder(encoding)、getdecoder(encoding)、getreader(encoding)和getwriter(encoding)方法;进一步,简化对特定字符编码的StreamReader、StreamWriter和StreamReaderWriter的访问,codecs更直接地提供了open方法,通过encoding参数传递字符编码名称,即可获得对encoder和decoder的双向服务。
    5/11/2006

    To check mail using poplib module

    import poplib

    def main():
        popsvr = "pop3.sohu.com"
        usr = "qcxhome"
        pwd = "*******"

        client = poplib.POP3(popsvr)
        client.user(usr)
        client.pass_(pwd)

        # Showing the number of mails in inbox
        msgcnt = client.stat()[0]
        print "The number of mails: %d" % (msgcnt)

        # Showing some information of each mail
        msgindex = 1
        while msgindex <= msgcnt:
            linebuf = client.top(msgindex, 0)[1]
            for s in linebuf:
                if s.startswith("From:") or s.startswith("Subject:"):
                    print s
            msgindex += 1
       
        client.quit()

    if __name__ == "__main__":
        main()
     
    上面这段脚本打印我的sohu信箱中每一封邮件的主题和发件人地址。当然打印的内容是邮件头中的原始信息,没有进行任何处理。
     
    使用poplib模块需要遵照POP3协议的会话流程调用相应的类方法:
    1、类POP3的构造函数建立与远程POP3服务器的TCP连接。构造函数有两个参数,第一个是必需的远程POP3服务器的主机名,亦域名。例如,pop3.sohu.com,pop3.sina.com.cn。第二个参数是可选的端口号,一般情况下不必使用这个参数,因为POP3协议默认使用25端口。
    2、登录POP3服务器,依次调用POP3.user(s)和POP3.pass_(s)方法,方法的参数你的邮件账户的用户名和密码。
    至此,您的Python脚本已经与远程POP3服务器建立了会话,此后便可以调用POP3类的其他方法获取邮件信息。这些方法与POP3邮件会话中的命令一一对应,可以说就是把命令行的形势直接转换成了方法调用的格式,您可以参考Python的类库参考和POP3协议来使用。
    最后,结束当前会话,调用POP3.quit()
     
    poplib模块让我们极为方便的操作自己的邮件信箱,使用Python可以针对特殊应用快速建立脚本。就我个人的一点经验来说,在poplib模块的外层还需要一个加工层,把POP3类方法返回的原始邮件信息转换为具有良好可读性的文本。因此我们还需要Python的其他一些模块完成以下任务:
    • 解释邮件头和邮件主体内容及附件
    • 将以某种格式编码的文本解码

    写到这里差不多了。从功能角度看,poplib模块提供了简单明了的原子功能。如果任务需要,在脚本中添加一行import poplib,你就能够操作POP3协议收邮件了。

     

    5/6/2006

    Sending email simply in Python

    # using smtplib module to send an email to my account qcxhome@sohu.com from sohu
    import smtplib

    from_addr = "qcxhome@sohu.com"
    to_addr = "qcxhome@sohu.com"
    msg = "Hi, shall we have lunch this afternoon? :)"

    client = smtplib.SMTP("smtp.sohu.com")
    client.login("qcxhome", "my_password")
    client.sendmail(from_addr, to_addr, msg)
    client.quit()