1. Keep Code Simple Not Data
l 减少代码,能减少生成的代码,因此能减少执行时间
2. 使用List Comprehensions构造List,快12倍
List Comprehension性能测试 |
|
使用List Comprehension使语法简洁,生成代码减少,执行显著加快 |
|
1 |
[i for i in range(10000000) if i % 2 == 0] |
测试结果 |
6 function calls in 2.494 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function) 1 0.000 0.000 2.491 2.491 :0(exec) 1 0.003 0.003 0.003 0.003 :0(setprofile) 1 0.000 0.000 2.491 2.491 <string>:1(<module>) 1 0.124 0.124 2.491 2.491 logtest.py:1(test1) 1 2.367 2.367 2.367 2.367 logtest.py:2(<listcomp>) 0 0.000 0.000 profile:0(profiler) 1 0.000 0.000 2.494 2.494 profile:0(test1()) |
2 |
def test2(): numbers = range(10000000) size = len(numbers) evens = [] i = 0 while i < size: if i % 2 == 0: evens.append(i) i += 1 |
测试结果 |
5000006 function calls in 30.718 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function) 5000000 13.001 0.000 13.001 0.000 :0(append) 1 0.000 0.000 30.715 30.715 :0(exec) 1 0.000 0.000 0.000 0.000 :0(len) 1 0.003 0.003 0.003 0.003 :0(setprofile) 1 0.142 0.142 30.715 30.715 <string>:1(<module>) 1 17.571 17.571 30.572 30.572 logtest.py:4(test2) 0 0.000 0.000 profile:0(profiler) 1 0.000 0.000 30.718 30.718 profile:0(test2()) |
3. 使用enumerate来获取index,快20%
enumerate性能测试 |
|
使用enumerate减少了索引计算语句,性能有20%提升 |
|
1 |
def test1(): ll = range(1000000) ret = [] for i, j in enumerate(ll): ret.append('%s, %s' % (i, j)) |
测试结果 |
1000005 function calls in 7.374 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function) 1000000 2.575 0.000 2.575 0.000 :0(append) 1 0.000 0.000 7.371 7.371 :0(exec) 1 0.003 0.003 0.003 0.003 :0(setprofile) 1 0.056 0.056 7.371 7.371 <string>:1(<module>) 1 4.739 4.739 7.315 7.315 logtest.py:9(test2) 0 0.000 0.000 profile:0(profiler) 1 0.000 0.000 7.374 7.374 profile:0(test1()) |
2 |
def test2(): ll = range(1000000) ret = [] index = 0 for i in ll: index += 1 ret.append('%s, %s' % (index, i)) |
测试结果 |
1000005 function calls in 7.430 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function) 1000000 2.575 0.000 2.575 0.000 :0(append) 1 0.000 0.000 7.428 7.428 :0(exec) 1 0.002 0.002 0.002 0.002 :0(setprofile) 1 0.055 0.055 7.427 7.427 <string>:1(<module>) 1 4.797 4.797 7.372 7.372 logtest.py:1(test1) 0 0.000 0.000 profile:0(profiler) 1 0.000 0.000 7.430 7.430 profile:0(test2()) |
4. 使用Generator处理循环/序列,节省内存
l List Comprehensions节省CPU, Generator节省内存
5. 使用multitask并发
l 使用multitask扩展模块和Generator可以实现简单的并发操作
multitask示例 |
>>> def coroutine_1(): for i in range(3): print 'c1' yield i >>> def coroutine_2(): for i in range(3): print 'c2' yield i >>> import multitask >>> multitask.add(coroutine_1()) >>> multitask.add(coroutine_2()) >>> multitask.run() c1 c2 c1 c2 c1 c2 |
6. 使用itertools迭代
itertools模块 |
itertools模块采用C语言编写,覆盖了大部分迭代模式, 主要有islice、tee和groupby |
Islice模式用来对子序列进行迭代 |
import itertools for x in itertools.islice('1234567890', 2, 5): #创建一个迭代下标范围为[2, 5)的迭代器 print(x) 3 4 5 for x in itertools.islice('1234567890', 5): #创建一个迭代头五个字符的迭代器 1 2 3 4 5 |
Tee模式用来从一个迭代器上创建多个独立的迭代器迭代 |
import itertools a, b = itertools.tee(‘abcdefghijklmnopqrstuvwxyz’, 2) #创建两个迭代器a, b, 用来迭代字符串 |
Groupby创建一个忽略连续重复字符的迭代器 |
import itertools for name, group in itertools.groupby(‘abbccc’): pass a, <迭代器for a> b, <迭代器for bb> c, <迭代器for ccc> |
7. 使用Decorator模式
Decorator使代码更加易读、灵活[参考链接]
l 用于参数检查
l 用于缓冲
l 用于代理
l 用于上下文提供
Decorator语法 |
|
不带参数的Decorator |
带参数的Decorator |
def decorator(func): return func
@decorator(): def example(num): print(num) example()
等价于 def example(num): print(num) dec = decorator(example) dec(num)
|
def decorator(logflags=True): if logflags == True: def _decorator(func): print(func.__name__) return func return _decorator else: return func
@decorator(logflags=True): def example(num): print(num) example()
等价于 def example(num): print(num) tmp = decorator(logflags=True) dec = tmp(example) dec(num) 一般多层嵌套的装饰器,建议加下划线的方式命名。每多嵌套一层,便多一个下划线。 |
8. 使用with替代try…finally
try…finally主要用于以下场景:
l Closing a file
l Releasing a lock
l Making a temporary code patch
l Running protected code in aspecial environment
由于try…finally结构写起来丑陋,因此使用with来代替try…finally
With使用示例 |
|
with_stmt ::= "with" with_item ("," with_item)* ":" suite with_item ::= expression ["as" target] |
|
使用with示例 |
定义支持with的类 |
fd = open(‘readme.txt’, ‘r) try: for line in fd: print line finally: fd.close() 可以写作 with open(‘readme.txt’, ‘r) as fd: for line in fd: print line |
class test(): def __enter__(self): print(‘enter context’)
def __exit__(self, exp_type, exp_value, exp_tb): print(‘exit context’) with test() as t: print(t) 当with中没有异常抛出时,传入__exit__的3个参数为None 当有异常抛出时,__exit__函数应该捕获该异常进行处理,不再抛出 |
@contextmanager使用示例 |
使用@contextmanager装饰的方法,会自动将方法中yield前面的语句放入__enter__中执行,后面的语句放入__exit__中执行。 在with中执行时, yield表达式作为提交给with的表达式结果 |
import logging from contextlib import contextmanager @contextmanager def logged(klass): # logger def _log(f): def __log(*args, **kw): logging.ERROR('%s, %s, %s' % (f.__name__, args, kw)) return f(*args, **kw) return __log #遍历类中的所有方法,并用__log方法装饰后,代替原来的方法 for attribute in dir(klass): #遍历非私有方法 if attribute.startswith('_'): continue #取得方法名(attrbute)对应的方法对象(element) element = getattr(klass, attribute) #使用__log封装该方法,并取名为__logged_attribute setattr(klass, '__logged_%s' % attribute, element) #将原有的attribue方法,替换为封装后的方法 setattr(klass, attribute, _log(element))
# let's work 执行到这里,返回给with语句,等待with语句执行完毕,再执行下面的语句 yield klass
# let's remove the logging for attribute in dir(klass): #遍历所有的__logged_开头,封装过的方法 if not attribute.startswith('__logged_'): continue element = getattr(klass, attribute) #将方法改名(去掉__logged_头) setattr(klass, attribute[len('__logged_'):], element) #删除__logged_头的方法 delattr(klass, attribute) |
class One(object): def _private(self): pass def one(self, other): self.two() other.thing(self) self._private() def two(self): pass
class Two(object): def thing(self, other): other.two()
with logged(One): #返回yield klass中的klass one = One() two = Two() one.one(two) |
closing使用示例(仅PYTHON 2.x) |
closing用于上下文对象执行完毕后,自动调用其close方法,将其关闭。PYTHON 3.x中已无该方法。 |
from contextlib import closing from urllib.request import urlopen
with closing(urlopen('http://www.python.org')) as page: for line in page: print(line)
等价于 from contextlib import contextmanager @contextmanager def closing(thing): try: yield thing finally: thing.close() |
Decorator模式和Proxy模式不同之处在于,Decorator只用来修饰某个方法,而Proxy模式代理的是一个功能(可能涉及到多个方法)。Decorator一般专用于方法,而Proxy用于类