Python提高早知道
用列表推导来取代map和filter
even_squares = [x**2 for x in a if x % 2 == 0]
randk_dict = {rank: name for name,rank in chile_ranks.items()}
alt = map(lambda x: x**2, filter(lambda x: x%2 ==0,a))
用生成器表达式来改写数据量较大的列表推导
- 把实现列表推导所所用的那种写法放在一对圆括号中,就构成了生成器表达式.
it = (len(x) for x in open(‘/tmp/my_file.txt’))
print(next(it))
- 逐次调用内置的next函数;
roots = ((x,x**0.5) for x in it)
print(next(roots))
- 当输入的数据量较大时,列表推导可能会因为占用太多内存而出问题.
- 由生成器表达式所返回的迭代器,可以逐次产生输出值,从而避免了内存用量的问题.
- 把某个生成器表达式所返回的迭代器,放在另一个生成器表达式的for子表达式中,即可将二者组合起来
- 串在一起的生成器表达式执行速度很快.
尽量用enumerate
取代range
for I , flavor in enumerate(flavor_list):
print('%d: %s'%(i+1,flavor))
enumerate
函数提供了一种精简的写法,可以在遍历迭代器时获知每个元素的索引.- 尽量用
enumerate
来改写那种将range
与下标访问相结合的序列遍历编码; - 可以为
enumerate
提供第二个参数,以指定开始计数时所用的值(默认为0
)
用zip函数同时遍历两个迭代器
for name, count in zip(names, letters):
if conunt > max_letters:
longest_name = name
max_letters = count
如果待遍历的迭代器长度不同,那么zip会提前终止,这将会导致意的结果.若不能确定zip所封装的列表是否等长,则可考虑改用itertools内置模块中的zip_longest
函数(python2中为izip_loongest
)
- 内置的
zip
函数可以平行地遍历多个迭代器. - python3中的zip相当于生成器,会在遍历过程中逐次产生元组,而python2中的
zip
则是直接把这些元组完全生成好,并一次性地返回整份列表. - 如果提供的迭代器长度不等,那么
zip
就会自动提前终止; itertools
内置模块中的zip_longest
函数可以平行地遍历多个迭代器,而不用在乎它们的长度是否相等;
尽量用异常来表示特殊情况,而不要返回None
考虑用生成器来改写直接返回列表的函数
生成器是使用yield
表达式的函数.调用生成器函数时,它并不会真的运行,而是会返回迭代器.每次在这个迭代器上面内置的next函数时,迭代器会生成器推进到下一个yield
表达式哪里.生成器穿黑yiled
的每一个值,都会由迭代器返回给调用者.
- 使用生成器比把收集到的结果放入列表里返回给调用者更加清晰;
- 由生成器函数所返回的那个迭代器,可以把生成器函数体中,传给
yield
表达式的那些值,逐次产生出来. - 无论输入量有多大,生成器都能产生一系列输出,因为这些输入量和输出量,都不会影响它在执行时所耗的内存.
- 解释器是读取并运行Python代码的计算机程序
子进程的运用
- 可以用subprocess模块运行子进程,病管理其输入流与输出流
- python解释器能够平行地运行多条子进程,这使得开发者可以充分运用其处理能力
- 可以给commnunicate传入timeout参数,以避免子进程死频或失去相应;(hanging,挂起
可以用线程来执行阻塞式I/O,但不要用它做平行计算
- 标准的python实现叫做CPython
- GIL(global interpreter lock 全局解释器锁),GIL实际上就是一把互斥锁(mutual-exclusion lock,又称为mutex,互斥体)。所谓占先式多线程切换,是指某个线程可以通过打断另外一个线程的方式,来获取程序控制权
- Python解释器会给每个线程分配大致相等的处理器时间。而为了达成这样的分配策略,Python系统能够可能当某个线程正在执行时候,将其暂停,然后使另外一个线程继续往下执行;
- 线程A执行到一半的时候,线程B插了进来,等线程B执行完整个递增操作之后,线程A又继续执行,于是线程A就把线程B刚才对计数器所做的递增效果,完全抹去了。传感器采样程序所统计到的样本总数之所有会出错。
- 最简单,最用用的工具,就是Lock类,该类相当于互斥锁(也叫做互斥体)
- Python确实存在全局解释器锁,但是在编写自己的程序时,依然要设法防止多个线程征用同一份数据。
- 如果不在加锁的前提下,允许多条线程修改同一个兑现,那么程序的数据结构可能会遭到破坏。
- 在python内置的threading的模块中,有名叫Lock的类,它用标准的方式实现了互斥锁
用Queue来协调各线程之间的工作
- Queue类使用工作线程无需再频繁地查询输入队列的状态,因为它的get方法会持续阻塞,知道新的数据加入。
- 线管是一种优秀的任务处理方式,它可以把处理流程划分为若干阶段,并使用多条python线程来同时执行这些任务
- 构建并发式的线管时,要注意许多问题。其中包括:如何防止某个阶段陷入持续等待的状态之中、如何停止工作线程,以及如何防止内存膨胀等
- Queue类所提供的机制,可以彻底解决上述问题,它具备阻塞式的队列操作能够制定缓存区尺寸,而且还支持join方法。
考虑用协程来并发地运行多个函数
- 协程工作原理:每当生成器函数执行到yield表达式的时候,消耗生成器的那段代码,就通过send方法给生成器回传一个值。而生成器在收到了经由send函数传进来的这个值后,会将其视为yield表达式的执行结果。
- 协程提供一种有效的方式,令程序看上去好像能够同时运行大量函数
- 对于生成器内的yield表达式来说,外部代码通过send方法传给生成器的那个值,就是该表达式所需要具备的值
- 协程是一种强大的工具,它可以把程序的核心逻辑,与程序同外部环境交互时所用的代码相分离
TypeError: unhashable type: ‘list’
s = set([1,2,3,4,4,5])
在使用list创建set的时候,一直出现TypeError: unhashable type: ‘list’,这种错误,检查代码,并没有出错,只可能是有些未知的错误,之前可能没有遇到过,百度后发现,原来是hash错误,就是list中的值不能hash。但是,set的创建也需要使用list,只能够在声明的时候直接使用list创建可以。
python对list去重的各种方法
1.直观方法
ids = [1,2,3,3,4,2,3,4,5,6,1]
news_ids = []
for id in ids:
if id not in news_ids:
news_ids.append(id)
print news_ids
2.用set
ids = [1,4,3,3,4,2,3,4,5,6,1]
ids = list(set(ids))
3.按照索引再次排序
ids = [1,4,3,3,4,2,3,4,5,6,1]
news_ids = list(set(ids))
news_ids.sort(key=ids.index)
4.使用itertools.grouby
ids = [1,4,3,3,4,2,3,4,5,6,1]
ids.sort()
it = itertools.groupby(ids)
for k, g in it:
print k
5.用reduce
ids = [1,4,3,3,4,2,3,4,5,6,1]
func = lambda x,y:x if y in x else x + [y]
reduce(func, [[], ] + ids)