cvmachine.com - 申博开户网

查找: 您的方位主页 > 网络频道 > 阅览资讯:Python常识介绍

Python常识介绍

2016-11-12 16:47:35 来历:www.cvmachine.com 【

Python常识介绍

今日同享的这篇文章,文字不多,代码为主。肯定干货,童叟无欺,首要同享了进步 Python 功用的 20 个技巧,教你怎样离别慢Python。原文作者 开元,全栈程序员,运用 Python, Java, PHP和C++。

1. 优化算法时刻复杂度

算法的时刻复杂度对程序的履行功率影响最大,在Python中能够经过挑选适宜的数据结构来优化时刻复杂度,如list和set查找某一个元素的时刻复杂度别离是O(n)和O(1)。不同的场景有不同的优化方法,总得来说,一般有分治,分支边界,贪心,动态规划等思维。

2. 削减冗余数据

如用上三角或下三角的方法去保存一个大的对称矩阵。在0元素占大多数的矩阵里运用稀少矩阵表明。

3. 合理运用copy与deepcopy

关于dict和list等数据结构的目标,直接赋值运用的是引证的方法。而有些状况下需求仿制整个目标,这时能够运用copy包里的copy和deepcopy,这两个函数的不同之处在于后者是递归仿制的。功率也不一样:(以下程序在ipython中运转)

import copy
a = range(100000)
%timeit -n 10 copy.copy(a) # 运转10次 copy.copy(a)

%timeit -n 10 copy.deepcopy(a)
10 loops, best of 3: 1.55 ms per loop
10 loops, best of 3: 151 ms per loop

timeit后边的-n表明运转的次数,后两行对应的是两个timeit的输出,下同。由此可见后者慢一个数量级。

4. 运用dict或set查找元素

Python dict和set都是运用hash表来完成(相似c++11规范库中unordered_map),查找元素的时刻复杂度是O(1)。

a = range(1000)
s = set(a)
d = dict((i,1) for i in a)
%timeit -n 10000 100 in d
%timeit -n 10000 100 in s
10000 loops, best of 3: 43.5 ns per loop
10000 loops, best of 3: 49.6 ns per loop

dict的功率略高(占用的空间也多一些)。

5. 合理运用生成器(generator)和yield

%timeit -n 100 a = (i for i in range(100000))
%timeit -n 100 b = [i for i in range(100000)]
100 loops, best of 3: 1.54 ms per loop
100 loops, best of 3: 4.56 ms per loop

运用()得到的是一个generator目标,所需求的内存空间与列表的巨细无关,所以功率会高一些。在具体应用上,比方set(i for i in range(100000))会比set([i for i in range(100000)])快。

可是关于需求循环遍历的状况:

%timeit -n 10 for x in (i for i in range(100000)): pass
%timeit -n 10 for x in [i for i in range(100000)]: pass

10 loops, best of 3: 6.51 ms per loop
10 loops, best of 3: 5.54 ms per loop

后者的功率反而更高,可是假如循环里有break,用generator的长处是清楚明了的。yield也是用于创立generator:

def yield_func(ls):
 for i in ls:
  yield i+1

def not_yield_func(ls):
 return [i+1 for i in ls]

ls = range(1000000)
%timeit -n 10 for i in yield_func(ls):pass

%timeit -n 10 for i in not_yield_func(ls):pass

10 loops, best of 3: 63.8 ms per loop
10 loops, best of 3: 62.9 ms per loop

关于内存不是十分大的list,能够直接回来一个list,可是可读性yield更佳(人个喜爱)。
python2.x内置generator功用的有xrange函数、itertools包等。

6. 优化循环

循环之外能做的事不要放在循环内,比方下面的优化能够快一倍:

a = range(10000)
size_a = len(a)
%timeit -n 1000 for i in a: k = len(a)
%timeit -n 1000 for i in a: k = size_a
1000 loops, best of 3: 569 µs per loop
1000 loops, best of 3: 256 µs per loop

7. 优化包括多个判别表达式的次序

关于and,应该把满意条件少的放在前面,关于or,把满意条件多的放在前面。如:

a = range(2000) 
%timeit -n 100 [i for i in a if 10 < i < 20 or 1000 < i < 2000]
%timeit -n 100 [i for i in a if 1000 < i < 2000 or 100 < i < 20]  
%timeit -n 100 [i for i in a if i % 2 == 0 and i > 1900]
%timeit -n 100 [i for i in a if i > 1900 and i % 2 == 0]
100 loops, best of 3: 287 µs per loop
100 loops, best of 3: 214 µs per loop
100 loops, best of 3: 128 µs per loop
100 loops, best of 3: 56.1 µs per loop

8. 运用join兼并迭代器中的字符串

In [1]: %%timeit
 ...: s = ''
 ...: for i in a:
 ...:   s += i
 ...:
10000 loops, best of 3: 59.8 µs per loop

In [2]: %%timeit
s = ''.join(a)
 ...:
100000 loops, best of 3: 11.8 µs per loop

join关于累加的方法,有大约5倍的进步。

9. 挑选适宜的格式化字符方法

s1, s2 = 'ax', 'bx'

%timeit -n 100000 'abc%s%s' % (s1, s2)
%timeit -n 100000 'abc{0}{1}'.format(s1, s2)
%timeit -n 100000 'abc' + s1 + s2
100000 loops, best of 3: 183 ns per loop
100000 loops, best of 3: 169 ns per loop
100000 loops, best of 3: 103 ns per loop

三种状况中,%的方法是最慢的,可是三者的距离并不大(都十分快)。(个人觉得%的可读性最好)

10. 不凭借中心变量交流两个变量的值

In [3]: %%timeit -n 10000
 a,b=1,2
 ....: c=a;a=b;b=c;
 ....:
10000 loops, best of 3: 172 ns per loop

In [4]: %%timeit -n 10000

a,b=1,2a,b=b,a
 ....:
10000 loops, best of 3: 86 ns per loop

运用a,b=b,a而不是c=a;a=b;b=c;来交流a,b的值,能够快1倍以上。

11. 运用if is

a = range(10000)
%timeit -n 100 [i for i in a if i == True]
%timeit -n 100 [i for i in a if i is True]
100 loops, best of 3: 531 µs per loop
100 loops, best of 3: 362 µs per loop

运用 if is True 比 if == True 将近快一倍。

12. 运用级联比较x < y < z

x, y, z = 1,2,3

%timeit -n 1000000 if x < y < z:pass
%timeit -n 1000000 if x < y and y < z:pass

1000000 loops, best of 3: 101 ns per loop
1000000 loops, best of 3: 121 ns per loop

x < y < z功率略高,并且可读性更好。

13. while 1 比 while True 更快

def while_1():
 n = 100000
 while 1:
  n -= 1
  if n <= 0: break

def while_true():
 n = 100000
 while True:
  n -= 1
  if n <= 0: break

m, n = 1000000, 1000000

%timeit -n 100 while_1()
%timeit -n 100 while_true()
100 loops, best of 3: 3.69 ms per loop
100 loops, best of 3: 5.61 ms per loop

while 1 比 while true快许多,原因是在python2.x中,True是一个全局变量,而非关键字。

14. 运用**而不是pow

%timeit -n 10000 c = pow(2,20)
%timeit -n 10000 c = 2**20

10000 loops, best of 3: 284 ns per loop
10000 loops, best of 3: 16.9 ns per loop

**便是快10倍以上!

15. 运用 cProfile, cStringIO 和 cPickle等用c完成相同功用(别离对应profile, StringIO, pickle)的包

import cPickle
import pickle
a = range(10000)
%timeit -n 100 x = cPickle.dumps(a)
%timeit -n 100 x = pickle.dumps(a)
100 loops, best of 3: 1.58 ms per loop
100 loops, best of 3: 17 ms per loop

由c完成的包,速度快10倍以上!

16. 运用最佳的反序列化方法

下面比较了eval, cPickle, json方法三种对相应字符串反序列化的功率:

import json
import cPickle
a = range(10000)
s1 = str(a)
s2 = cPickle.dumps(a)
s3 = json.dumps(a)
%timeit -n 100 x = eval(s1)
%timeit -n 100 x = cPickle.loads(s2)
%timeit -n 100 x = json.loads(s3)
100 loops, best of 3: 16.8 ms per loop
100 loops, best of 3: 2.02 ms per loop
100 loops, best of 3: 798 µs per loop

可见json比cPickle快近3倍,比eval快20多倍。

17. 运用C扩展(Extension)

现在首要有CPython(python最常见的完成的方法)原生API, ctypes,Cython,cffi三种方法,它们的效果是使得Python程序能够调用由C编译成的动态链接库,其特色别离是:

CPython原生API: 经过引进Python.h头文件,对应的C程序中能够直接运用Python的数据结构。完成进程相对繁琐,可是有比较大的适用范围。
ctypes: 一般用于封装(wrap)C程序,让纯Python程序调用动态链接库(Windows中的dll或Unix中的so文件)中的函数。假如想要在python中运用已经有C类库,运用ctypes是很好的挑选,有一些基准测验下,python2+ctypes是功用最好的方法。
Cython: Cython是CPython的超集,用于简化编写C扩展的进程。Cython的长处是语法简练,能够很好地兼容numpy等包括很多C扩展的库。Cython的使得场景一般是针对项目中某个算法或进程的优化。在某些测验中,能够有几百倍的功用进步。
cffi: cffi的便是ctypes在pypy(详见下文)中的完成,同进也兼容CPython。cffi供给了在python运用C类库的方法,能够直接在python代码中编写C代码,一起支撑链接到已有的C类库。
运用这些优化方法一般是针对已有项目功用瓶颈模块的优化,能够在少数改动原有项目的状况下大幅度地进步整个程序的运转功率。

18. 并行编程

因为GIL的存在,Python很难充分运用多核CPU的优势。可是,能够经过内置的模块multiprocessing完成下面几种并行形式:

多进程:关于CPU密集型的程序,能够运用multiprocessing的Process,Pool等封装好的类,经过多进程的方法完成并行计算。可是因为进程中的通讯本钱比较大,关于进程之间需求很多数据交互的程序功率未必有大的进步。
多线程:关于IO密集型的程序,multiprocessing.dummy模块运用multiprocessing的接口封装threading,使得多线程编程也变得十分轻松(比方能够运用Pool的map接口,简练高效)。
分布式:multiprocessing中的Managers类供给了能够在不同进程之同享数据的方法,能够在此基础上开宣布分布式的程序。
不同的事务场景能够挑选其间的一种或几种的组合完成程序功用的优化。

19. 终级大杀器:PyPy

PyPy是用RPython(CPython的子集)完成的Python,依据官网的基准测验数据,它比CPython完成的Python要快6倍以上。快的原因是运用了Just-in-Time(JIT)编译器,即动态编译器,与静态编译器(如gcc,javac等)不同,它是运用程序运转的进程的数据进行优化。因为前史原因,现在pypy中还保留着GIL,不过正在进行的STM项目企图将PyPy变成没有GIL的Python。

假如python程序中含有C扩展(非cffi的方法),JIT的优化效果会大打折扣,乃至比CPython慢(比Numpy)。所以在PyPy中最好用纯Python或运用cffi扩展。

跟着STM,Numpy等项目的完善,信任PyPy将会代替CPython。

20. 运用功用剖析东西

除了上面在ipython运用到的timeit模块,还有cProfile。cProfile的运用方法也十分简略:python -m cProfile filename.py,filename.py 是要运转程序的文件名,能够在规范输出中看到每一个函数被调用的次数和运转的时刻,然后找到程序的功用瓶颈,然后能够有针对性地优化。

以上便是本文的全部内容,期望对咱们的学习有所协助,也期望咱们多多支撑申博开户。


本文地址:http://www.cvmachine.com/a/question/82139.html
Tags: python 你的 20招
修改:申博开户网
关于咱们 | 联络咱们 | 友情链接 | 网站地图 | Sitemap | App | 回来顶部