python中创建singleton的方法

名称覆盖


class MyClass(object):
    pass

MyClass = MyClass()

这是最简单粗暴的方法,直接用MyClass对象覆盖了同名的类,这样后面的代码就看不到MyClass类了也就不能继续生成这个类对应的对象了。

保存已经存在的类对象


G_INSTANCES = {}

def get_ins(cls, *args, **kwargs):
    if cls not in G_INSTANCES:
        G_INSTANCES[cls] = cls(*args, **kwargs)
    return G_INSTANCES[cls]

class MyClass(object):
    pass

c1 = get_ins(MyClass)
c2 = get_ins(MyClass)
assert id(c1) == id(c2)

使用全局dict保存已经创建过的类对象,下次创建时如果已经存在直接返回。

使用闭包优化上一个方法


def singleton …
more ...

python print 重定向到文件时编码错误

使用python print的时候经常遇到一个奇怪的问题:

print unicode时,如果unicode包含中文,输出到屏幕时一切正常,但是把屏幕输出重定向到文件时,却报编码错误。错误内容大致如下:

UnicodeEncodeError: 'ascii' codec can\'t encode characters in position
0-1: ordinal not in range(128)

原因是这样的:

  1. 因为你的屏幕显示编码是utf8格式的,所以python知道使用utf8来对unicode进行编码
  2. 重定向到文件时,python并不知道文件格式是什么,所以只能使用默认的ascii来进行编码,而ascii不能对中文进行编码,就会看到前面的异常
  3. 其实不仅仅是编码中文时会遇到异常,只要编码的值超过128(ascii表是使用7位的)都会异常

怎么快速解决这个问题呢?

  1. 在代码中以UTF-8的方式打开文件,然后写文件
  2. print unicode之前,显示按str的来源方式编码,比如utf8。原来的print需要改为print ucontent.encode(‘uft8’)
  3. env …
more ...

问号 ( ? ) 在python正则分组中的用法

非捕获分组 (Non-capturing Groups):

首先是上次文章提到一个非捕获分组的用法:

>>> print a
a123b123b
>>> print re.match(r"a(123)", a).groups()
('123',)
>>> print re.match(r"a(?:123)", a).groups()
()
>>> print re.match(r"a(?:123)", a).group()
a123

非捕获分组,即该分组不记录在最终的groups中,但是还是会匹配的

命名分组 (Named Groups):

>>> print a
a123b123b
>>> print re.match(r"a(?P<namedgroup1>[1-3 …
more ...

python 打印数字的正负号

python中使用print "%d"%i时,默认是不显示"+"号的:

>>> print "%d"%123  
123  
>>> print "%d"%-123  
-123

有没有方法在print "%d"%123显示"+123"呢? 很幸运,是有的,使用print "%+-d"%123print "%+d"%123即可。

more ...

python join不响应信号

python在写多线程程序时,发现多线程启动之后,用ctrl+c终止不了了,之前也没太关注,因为用kill -9还是可以终止的。

今天在写为一个python程序写一个signal handler的时候,发现竟然不生效。仔细研究了一下才发现,原来是当调用Thread.join之后,程序就不再能响应信号了(-9除外)。这应该就是之前ctrl+c不生效的原因,因为ctrl+c实际就是发了一个SIGINT信号。

为了要实现signal handler的问题,不能继续使用Thread.join了,只能使用下面的代码代替了:

while threading.activeCount > 1:
    time.sleep(interval)

循环检测剩余的线程数,如果线程数大于1,证明还有子线程未退出,那么进入sleep等待。

这样实现可以绕过Threading.join之后不能响应信号的问题,不过缺点是会占用额外的CPU资源。占用多少CPU资源,要视循环间隔而定(即interval的值大小)。

more ...

如何用C/C++扩展Python的功能

用c/c++扩展Python功能,说简单点就是python中调用c/c++代码,比较基础的有两种方式:

  1. 使用Python的C语言接口,即通过PyObject,这篇文章介绍比较详细。
  2. 使用ctypes直接导入c/c++动态库,如何使用点这里

第一种方式编写c/c++接口稍微麻烦一点,但是在python代码中使用该接口会十分方便,如同使用内置模块一般;第二种方式则可以直接使用原有的c/c++动态库,即使没有源文件也可以使用。

两种使用方式在其他方面,比如效率,是否还有区别,目前还没有研究过。

more ...

查看运行中的python脚本的堆栈

对于c/c++程序,我们可以在运行过程中通过pstack来查看程序当前的执行堆栈。

那么对于python脚本呢?

方法一

如果脚本是前台运行,可以直接Ctrl+c中止该脚本,即可查看当前的执行堆栈。

如果脚本是后台运行的,可以先fg jobid,然后直接Ctrl+c中止脚本。当前的执行堆栈会被打印到脚本后台运行时的输出中 如果是./test.py &运行则是输出到前台;如果是nohup ./test.py &运行则是输出到nohup.out;如果加了输出重定向,则是打印到重定向的输出文件中

方法二:

通过pdb完成,主要是为python脚本设置一个signal_handler,在其hang住的时候发送信号给它,然后进入debug模式。这时可以用w命令打印出当前执行堆栈。

参考这篇文章

不过这个方式,对后台运行的程序无效(不管是否先将程序转到前台)。而且需要提前加部分代码,对于已经在运行中的脚本无效。

好处是,如果程序是前台运行的,进入debug模式之后还可以继续运行,而不像方法一直接就终止脚本了。(有一点要注意的是:如果脚本处于sleep状态,经过信号处理之后sleep就被唤醒了)

方法三 …

more ...

python MySQLdb的初步使用

MySQLdb库使用还是比较简单的,了解了几个API就可以开始捣腾了。

这里有一些API的说明

基本使用步骤:

  1. 导入MySQLdb库:import MySQLdb
  2. 建立一个DB连接:db_con = MySQLdb.connect(DB_host,DB_user,DB_password,DB_database)
  3. 执行命令:db_con.query(sql_cmd) 或者 cursor = db_con.cursor(); cursor.excute(sql_cmd); cursor.close()
  4. 获取返回值:db_con.store_result().fetch_row(),这个返回值是一个二元元组。比如要获取返回值的第一列第一行就是db_con.store_result().fetch_row()[0][0]
  5. 关闭连接:db_con.close()

有一点比较需要注意的是:

store_result()fetch_row()函数并不仅是返回某个值这么简单,而是有副作用的,调用一次之后会清除原来的结果 …

more ...

python中如何中止一个线程

今天遇到一个需求,希望可以实现一个带时间上限的线程池的功能,需要在到达时间上限的时候,主动kill掉那些slave线程。

找了很久,终于发现一个基本满足需求的实现。

记录在这里,以备不时之需。

class KillableThread(threading.Thread):
    """A subclass of threading.Thread, with a kill() method."""
    def __init__(self, *args, **keywords):
        threading.Thread.__init__(self, *args, **keywords)
        self.killed = False

    def start(self):
        """Start the thread."""
        self.__run_backup = self.run
        self.run = self.__run # Force …
more ...