优雅地使用python

1、if-else

a=2b=3x = 3 if (a==2 and b==3) else 0#相当于if a==2 and b==3:   x = 3else:   x = 0#显然第一种写法更优雅,读起来也更自然,这种语法是python2.7以上版本的新特性if all(x > 3 for x in lst): #python2.6以上版本语法    do_sth()#相当于for x in lst:  if x <= 3:     return Falsereturn True

2、xrange  在for循环中使用xrange代替range,可以节省内存和提高性能,如下:

#Yes:for i in xrange(0,10):    print i#No:for i in range(0,10):    print i

  这是因为range函数返回一个list对象,而xrange会返回一个generator对象。关于generator的特性我准备通过下面的一段代码来说明:

def fun1():    yield 1    yield 2    yield 3def fun2():    return [1,2,3]# 下面两个循环会得到一样的输出for i in fun1():    print ifor i in fun2():    print i

  这里的fun1可以看成是我们构造的一个类generator,当我们调用fun1的时候,函数会在yield语句处暂停,然后返回当前的值并储存函数的调用状态,当下一次调用时,函数会从上次停止的状态继续执行,直到下一个yield语句。  回到range和xrange上,这里我们讨论的是python2下面的情况,在python3里,xrange消失了,range则表现得跟原来的xrange一样了,这种情况下如果确实要得到一个list,就得用这种方式: list(range())

3、为无限循环使用 while 1 代替 while True  这是因为,在python2里,True不是一个关键字而只是一个全局变量,而 while 1 就只是一个单步操作。

4、用join()进行字符串拼接  这里先要说明一下,在python中,一个对象一但创建,它在内存中的大小就是不变的了,那些需要容纳可变长度数据的对象只能在对象内维护一个指向一块可变大小内存区域的指针,这么设计主要是为了方便内存管理和对象管理。  而对于用 + 来拼接str,如 a+=b ,因为python中字符串对象长度不可变,这里就需要先创建一个新的字符串对象,再将a和b复制过去,因此对于大量的字符串拼接,应当尽可能使用”.join()的方式。两种这点在PEP8里也有提及如下:

text=''#Nofor svr in svrlist:   text += svr + 'n'#Yestext = 'n'.join(svrlist)

5、写简洁的list  python支持如下一种简洁而优雅的构造list的方法:

mylst = [i for i in range(10) if i%2 == 0]

6、交换变量

 x, y = y, x

7、尽量使用局部变量Python 检索局部变量比检索全局变量快. 这意味着,避免 “global” 关键字。

8、executemany  这个其实是MySQLdb的一个函数,单独拿出来讲主要是因为确实好用有性能提升,但又有个小坑。先上个简单的代码

sql = "insert into table values(%s)"sqlargvs=[i for i in xrange(1,10)]cursor.executemany(sql,sqlargvs)

  按help文档的说法,使用executemany比做个循环再使用execute,在insert和delete操作上有极大的性能提升。然而,当我们要插入的数据过多,大过于lmysql server设定的阀值时,就会爆出一个“max sockets”的错误(具体的错误码我忘了)。最后还是要用循环+execute的方式。  因此这个东西就有点鸡肋了,数据少时性能提升有限,数据大时有被爆菊的风险。。

9、decorator  decorator本质上是支持了在函数和类中嵌入或修改代码,下面的代码简单地介绍了其用法,首先是函数形式的:

class myDecorator(object):    def __init__(self, f):        print "init"        self.f = f    def __call__(self):        print "call"        self.f()if __name_- == "__main__":    @myDecorator    def func()        print "func"    print func.__class__    func()

  这段代码会输出:

init<class '__main__.entryExit'>callfunc

  也即当我们用@符号调用myDecorator时,函数对象func被传递给类myDecorator,然后创建了一个类函数对象取代原来的func()函数。当我们调用func()时,便不再用原来的代码而开始调用myDecorator.__call__()方法。这里要注意的是,用于decorator的类必须实现__call__方法。  以我粗浅的理解,这里的decorator的应用的场景应该是当我们有一个类,类里有比较复杂的实现,但我们外部的调用却只需一个简单接口即可以满足,这时候我们就可以通过decorator暴露出来,同时也可以在类中嵌入或修改代码(在func()函数中)  decorator也可用于函数,示例代码如下:

def myDecorator(f):    def newf()        print "inside newf"        f()    return newfif __name__ == "__main__":    @myDecorator    def func():        print "inside func"    print func.__name__    func()

  以上代码会输出:

newfinside newfinside func

  类似的,当decorator用于函数myDecorator,myDecorator()返回的必须是可调用的东西  在网上我也看到有人将decorator用于做缓存,下面是一个在网上到处能看到的用decorator做cache计算斐波那契数的例子:

def cache(func):    fibcache = {}    def wrap(n):        if n not in fibcache:            fibcache[n] = func(n)        return fibcache[n]    return wrap@cachedef fib(n):    if n < 2:        return 1    return fib(n-1) + fib(n-2)

  在这个例子使用decorator的优雅之处在于,他既做了cache,又无需改变原来的fib()。如果我们不用decorator,而是将字典fibcache设置为全局变量,并在fib()函数里做多一些判断,也同样能达到同样的cache的效果,但这样一来,代码就混乱了许多。

10、cProfile  最后再简单介绍一下cProfile这个工具,cProfile是profile的C语言版本,有着跟profile一样的接口,但效率比profile更高,两者都是python的标准库。可以统计程序里每一个函数的运行时间。这个模块用得最多就是cProfile.run(statement, filename=None, sort=-1)了,第一个参数statement是要统计的函数或命令,第二个参数是指定输出报表保存的文件名,如果未设定则输出到控制台,第三个参数是对输出进行排序,具体的值所对应的排序的种类,其实也就是pstats.Stats.sort_stats的排序参数,先上一个简单的代码:

def foo():    for i in xrange(100):        print iif __name__ == "__main__":    import cProfile    cProfile.run(statement="foo()",filename="prof",sort="calls")

  这里sort=”calls”是指按指令的调用次数排序。  cProfile也支持命令行的方式:

python -m profile -o prof testprof.py

  但对于保存到prof文件里的数据,是不能简单cat出来看的,得用pstats模块:

import pstatsp = pstats.Stats("prof")p.print_stats()#在pstats这也能再做排序p.sort_stats("time").print_stats()

  可选的排序选项可以在pstats的帮助文档里找到。

优雅地使用python

相关文章:

你感兴趣的文章:

标签云: