• 2015/5/4

1 关于快速排序, 仿照C++的快速排序写法可以写出风格比较相近的python code:

void foo(int s, int e){
    if(s >= e) return;
    int fst = a[s];
    int i = s, j = e;
    while(i < j){
        while(i < j && a[j] >= fst) --j;
        a[i] = a[j];
        while(i < j && a[i] <= fst) ++i;
        a[j] = a[i];
    }
    a[i] = fst;
    if(i > s) foo(s, i-1);
    if(i < e) foo(i+1, e);
} 

但是很容易写的不够pythonic, 比较pythonic的写法是:

def quicksort(array):
    less = []
    greater = []

    if len(array) <= 1:
        return array
    p = array.pop()
    for x in array:
        if x <= p: less.append(x)
        else: greater.append(x)
    return quicksort(less) + [p] + quicksort(greater)



2 交换两个数

在其他语言中, 交换两个数最常见的做法是加入一个中间值作为一个临时仓库(当然可以通过^避免中间变量:a ^= b, b ^= a, a ^= b), 而在python中一切都变得简单了: a, b = b, a 就可以交换两个数的值,可以这样做的原因如下:首先python赋值表达式的顺序是先计算右边的表达式,因此会先在内存里创建元组(b, a), 然后通过UNpacking(解包)的方式一一赋值给a,b.



3 字符串连接的问题

python字符串效率问题之一就是在连接字符串的时候使用‘+’号,但是使用+号的话,python需要申请N-1次内存空间,然后进行字符串拷贝。 原因是字符串对象PyStringObject在python当中是不可变对象,所以每当需要合并两个字符串的时候,就要重新申请一个新的内存空间(大小为两个字符串长度之和)来给这个合并之后的新字符串, 然后进行拷贝, 所以用+号效率非常低。

建议在连接字符串的时候使用字符串本身的方法join,这个方法能提高效率,原因是它只是申请了一次内存空间,因为它可以遍历list中的元素计算出总共需要申请的内存空间的大小,一次申请完。

#not pythonic 
list = ['a', 'b', 'c']  
ans = ''  
for i in list:  
    ans += i  

#pythonic  
list = ['a', 'b', 'c']  
ans = ''.join(list) 



4 输出列表的index和vlaue

给定一个列表, 输出每个元素对应的下标以及值时候, 可以有很多种方式, 比如range()迭代, zip()等等,但是最好的方式还是用enumerate()

li = ['a', 'b', 'c', 'd']
for idx, val in enumerate(li):
    print idx, val

enumerate()是在python2.3中引入的, 也是为了解决在循环中获取索引以及对应值的问题, 它本质上也是通过生成器yield生成的, 所以调用enumerate()返回的是一个可迭代对象, 这样做的好处很明显:具有一定的惰性, 可以仅在需要的时候产生数据。

5 关于map, filter, reduce

这几个都算是function programming的工具, 这里的function通常用匿名函数lambda来带入。其中reduce做一个递归计算, map对列表每一个元素做同样的操作, filter就是一个过滤器的作用。

z = reduce(lambda x, y: x+y, data, 0)   #reduce(function, sequence, starting_value)
print z

z = map(lambda x: x+1, data)   #map(function, sequence)
print z

z = filter(lambda x: x > 2, data)
print z

需要注意的是python3之后, 这几个函数返回的不是一个列表, 而仅仅是一个可迭代对象。

6 两个元素之间有对应关系的list构造一个dict, 运用zip可以非常简单的实现。

a, b = ["a", "b", "c"], [1,2,3]
m = dict(zip(a, b))


7 range 与 xrange

a = [i for i in xrange(5)] 和 a = (i for i in xrange(5)) 虽然看上去是一样都生成了5个元素,但是 前者是一个list对象, 如果遍历的话 for item in a 就会一下子返回全部元素然后再遍历, 而后者是个generator, 用for item in a遍历是每次只是返回一个元素, 这样的好处是省内存(在list很大的情况下)。

8 用Decorator抽离公用代码或者解耦

在django里面, 装饰器用的非常多,例如要对一个函数做cache,对一个操作限制权限,如果需求随时可能变化,就是说有可能不需要做cache或者不需要做权限的时候,你如果把实现放到这些函数体里面,那么这时你必须把这些代码删除,而且要很小心。但是如果你用decorator去做的话, 只要删除函数头顶上的@那一行就可以了, 非常的pythonic。

相似文章


最近发表的文章

全部文章

评论区

comments powered by Disqus 回到顶部