字符串拼接的效率

资深一点的python开发者肯定知道如果要把很多小的字符串拼接起来,用''.join的方式效率最高。

最近遇到一个字符串拼接的问题,比较有意思,记录一下。

场景是,在开发thrift序列化库的时候,产生了一个字符串类型的链表,最终要把链表中的字符串拼接成一个整串,并在前面加上整个字符串的长度。

最原始的实现是:

def list_join_and_concat(_list):
    msg = ''.join(_list)
    return pack('!i', len(msg)) + msg

写的过程中发现这里有个字符串相加的操作,而且msg这个字符串对象比较大,担心对效率有影响,因此思考一下是否有别的实现方案。

为了消除字符串相加,想了两个方案:

def list_insert_join(_list):
    length = sum(map(len, _list))
    _list.insert(0, pack('!i', length))
    return ''.join(_list …
more ...

SQLAlchemy数据库连接被关闭

最近在使用SQLAlchemy做一个后台server时,发现server启动一段时间之后偶尔会出现"MySQL has gone away"的错误。

研究了一下发现是因为MySQL默认会关掉空闲的连接,默认是28800秒,即8小时。

而后台server起来之后,如果8小时没有请求没有数据库操作,那么8小时之后原来的数据库连接就被MySQL关闭了,后面SQLAlchemy再使用该连接操作数据库的时候就会报"MySQL has gone away"的错误。

需要解决此问题,只需要在create_engine时加上pool-recycle即可,详细说明可参考官方文档

more ...

在python列表推导中使用lambda可能遇到的问题

相信python代码写多了人应该都会遇到或见过下面这种情况:

functions = [lambda x: i*x for i in xrange(5)]
[f(2) for f in functions]

输出结果:[8,8,8,8,8],而并不是[0,2,4,6,8]


原因是: 使用lambda生成的匿名函数的时候,并没有立即查找i并求值,在函数被调用时才会查找i并求值,而在函数被调用的时候i的值是4。

比如你定义一个函数,引用一个不存在的变量,在函数定义的时候并不会报错,只有函数被调用的时候才会提示找不到变量:

f = lambda x: nonexist_i*x
f …
more ...

python修改对象从属关系和类继承关系

修改对象从属关系

其实这里想介绍的一个神奇的函数__instancecheck__,它的描述文档在这里

The primary mechanism proposed here is to allow overloading the built-in functions isinstance() and issubclass() . The overloading works as follows: The call isinstance(x, C) first checks whether C._instancecheck_ exists, and if so, calls C._instancecheck_(x) instead of its normal implementation …

more ...

慎用python的__del__方法

python的__del__方法是什么?

和C++的destructor有点类似,在对象销毁的时候,会调用对象的__del__方法,但是,但是有些区别。

有哪些区别呢?

调用时机

在C++里面,对象是用户手工管理的,用户通过显示地调用delete obj来销毁对象obj,对象销毁时对象的destructor会被调用。

而在python里面,用户不需要手工管理对象,python自带的垃圾回收机制会通过引用计数来判断对象是否可以销毁。当一个对象的引用计数为0时,python解析器会自动销毁该对象,同时调用该对象的__del__方法。

也就是说del obj在python里面并不一定会销毁一个对象,只是让该对象的引用计数减一。

"del x" doesn't directly call x.__del__() — the former decrements the reference count for x by …

more ...

python解释器退出时new style class的类属性的__del__方法不会被调用

先看看如下一段代码输出什么:

class A(object):
    def __init__(self):
        print "A init"

    def __del__(self):
        print "A del"


class B(object):
    a = A()
    #def __init__(self, a=A()):
    #    self.a = a

print "test"

输出:

A init
test

就因为这个问题,导致我的一个程序资源泄露了:( 而之前这个程序已经正常运行了半年了,只是某次升级的时候,我顺手把A和B从old style class改成new style class了。

以后切记:不要把资源释放的工作放在__del__方法中,这个方法的会不会被调用、会被调用几次,实在有太多的不确定因素了。python …

more ...

采坑记录:python json不支持int类型key

最近踩了一个很好玩的坑:

在python中将key为int类型的dict通过json.dumps出来之后,再用json.loads转为为dict时,发现原来int类型的key变成了str类型

>>> d={1:2}
>>> dump = json.dumps(d)
>>> d
{1: 2}
>>> dump
'{"1": 2}'
>>> d1 = json.loads(dump)
>>> d1
{u'1': 2}

后来google搜了一下,发现和我踩过同样坑的人还不少:

http://stackoverflow.com/questions/17099556/why-do-int-keys-of-a-python-dict-turn-into-strings-when-using-json-dumps http://stackoverflow.com/questions/1450957/pythons-json-module-converts-int-dictionary-keys-to-strings

more ...

将xfe格式的unicode转化为u00fe格式

python 2.x中的unicode,如果某个字符位于80和ff之间,默认是用单字节表示的:

>>> s=u'··'
>>> s
u'\xb7\xb7'
>>> print "%r" % s
u'\xb7\xb7'

如果想转化\u00b7的格式呢? 正像我在这个问题回答一样,json.dumps可以用来做这个事情:

>>> s=u'··'
>>> json.dumps(s)
'"\\u00b7\\u00b7"'
>>> print json.dumps(s)
"\u00b7\u00b7"
more ...

python iterator 和 generator

iterator

iterator是一个概念(或者认为是类型集合),而非某个具体类型,是指实现了如下两个方法的类型:

  1. __iter__() 返回iterator对象本身
  2. next() 返回下一个元素

例如,存在一些属于iterator的类型,但并没有iterator这种类型

>>> l=[]
>>> type(l.__iter__())
<type 'listiterator'>
>>> d={}
>>> type(d.iterkeys())
<type 'dictionary-keyiterator'>
>>> type(d.iteritems())
<type 'dictionary-itemiterator'>
>>> type(d.itervalues())
<type 'dictionary-valueiterator'>

generator

generator属于iterator,因为其实现了__iter__next方法:

>>> type(g)
<type 'generator'>
>>> dir(g)
['__class__ …
more ...

python精美片段之找出list中符合条件的第一个元素

第一种写法

e = None
for i in l:
    if condition(i):
        e = i
        break

缺点:不美观

第二种写法

e = [i for i in l if condition(i)][0]
e = filter(condition, l)[0]

缺点:没有做list非空判断可能异常;效率不高,只需要一个元素,但是遍历了原始list所有元素

第三种写法

e = next((i for i in l if condition(i)), None)
e = next …
more ...