python的使用技巧

1 流式读取数G大文件

使用read方法,指定每次指定读取固定大小的内容。下面的代码每次只读取8K的数据
方法一

def read_from_file(filename,block_size= 1024*8):
	with open(filename,'r') as fp:
		while True:
			chunk = fp.read(block_size)
			if not chunk:
				break
			yield chunk

方法二
借助辅助函数

from functools import partial

def read_from_file(filename,block_size=1024*8):
	with open(filename,'r') as fp:
		for chunk in iter(partial(fp.read,block_size)):
			yield chunk

2 利用自带的缓存机制提高代码的运行效率

缓存是一种将定量数据加以保存,以备迎合后续需求的处理方式,旨在加快数据获取的速度。在实际的工程中数据的生成过程中可能需要经过计算,规整、远程获取等操作,如果是同一份数据需要多次使用,每次都重新生成会大大浪费时间。所以,如果将计算或者远程请求等操作获取得得数据缓存下来,会加快后续得数据获取需求。为了实现该需求,python中提供了一个方法,使用functool模块中得lru_cache装饰器

@functools.lru_cache(maxsize=None, typed=False)

参数解读:

  • maxsize:最多可以缓存多少个此函数的调用结果,如果为None,则无限制,设置为 2 的幂时,性能最佳
  • typed:若为 True,则不同参数类型的调用将分别缓存。
from functools import lru_cache
@lru_cache(None)
def add(x,y):
	print('calculating:%s+%s'%(x,y))
	return x+y
print(add(1,2))
print(add(1,2))
print(add(7,2))

输出:

calculating: 3 + 3
3
3
calculating: 7 + 2
9

从上面得代码可以看出,第一次调用时执行了函数,而第二次并没有执行函数,而是直接返回缓存得结果。第三次当传入新的数据时开始调用函数。

测试该方法的运行速度。

import timeit

def fib(n):
    if n < 2:
        return n
    return fib(n - 2) + fib(n - 1)
#使用timeit测试运行的时间,单位为s(秒)
print(timeit.timeit(lambda :fib(40), number=1))
# output: 31.2725698948
import timeit
from functools import lru_cache

@lru_cache(None)
def fib(n):
    if n < 2:
        return n
    return fib(n - 2) + fib(n - 1)

print(timeit.timeit(lambda :fib(500), number=1))
# output: 0.0004921059880871326

由上可以发现,在使用lru_cache速度加快很多。

3 print函数将输出写入日志中

print函数可以将结果打印在控制台中,同时也可以将结果输入文件中。

with open('aa.log','w') as f:
	print('hahahah',file=f,flush=True)

参数解读:
flush:
功能:把缓冲区的数据强行输出,清空缓冲区。
作用:

  • 在该问题下:在读写流中数据先被读到内存(相当于缓存区),再写入,中途用close()方法关闭读写流,缓存数据会丢失。
  • 用flush()方法:刷新缓存区,强制把其中数据写入文件,清空缓冲区,避免数据丢失。
  • 在print里flush默认是False,写成True后每次调用执行该语句时,都会把语句的内容放到文件中(如果有用file方法的话)。

4 将嵌套循环改写成单循环

在实际中我们常常使用嵌套循环,for

import numpy as np
a = np.arange(1,10)
b = np.arange(1,10)
c = np.arange(1,10)
for i in a:
	for j in b:
		for k in c:
			print(k+j+i)

该方法很丑,可以使用itertools中的product进行替换

from itertools import product
import numpy as np
a = np.arange(1,10)
b = np.arange(1,10)
c = np.arange(1,10)

for i,j,k in product(a,b,c):
	print(i+j+k)

输出结果

3
4
5
6
7
8
.
.
.

关闭异常自动关联上下文

当你在处理异常时,由于处理不当或者其他问题,再次抛出另一个异常时,往外抛出的异常也会携带原始的异常信息。如下所示。

try:
    print(1 / 0)
except Exception as exc:
    raise RuntimeError("Something bad happened")

从输出可以看到两个异常信息

Traceback (most recent call last):
  File "demo.py", line 2, in <module>
    print(1 / 0)
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "demo.py", line 4, in <module>
    raise RuntimeError("Something bad happened")
RuntimeError: Something bad happened

如果在异常处理程序或 finally块中引发异常,默认情况下,异常机制会隐式工作会将先前的异常附加为新异常的```context``属性。这就是 Python 默认开启的自动关联异常上下文。

如果你想自己控制这个上下文,可以加个 from 关键字(from语法会有个限制,就是第二个表达式必须是另一个异常类或实例。),来表明你的新异常是直接由哪个异常引起的。

try:
    print(1 / 0)
except Exception as exc:
    raise RuntimeError("Something bad happened") from exc

输出如下

Traceback (most recent call last):
  File "demo.py", line 2, in <module>
    print(1 / 0)
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "demo.py", line 4, in <module>
    raise RuntimeError("Something bad happened") from exc
RuntimeError: Something bad happened

当然,你也可以通过with_traceback()方法为异常设置上下文__context__属性,这也能在traceback更好的显示异常信息。

try:
    print(1 / 0)
except Exception as exc:
    raise RuntimeError("bad thing").with_traceback(exc)

最后,如果我想彻底关闭这个自动关联异常上下文的机制?有什么办法呢?

可以使用 raise...from None,从下面的例子上看,已经没有了原始异常

$ cat demo.py
try:
    print(1 / 0)
except Exception as exc:
    raise RuntimeError("Something bad happened") from None
$
$ python demo.py
Traceback (most recent call last):
  File "demo.py", line 4, in <module>
    raise RuntimeError("Something bad happened") from None
RuntimeError: Something bad happened
(PythonCodingTime)

参考文献

5 年 Python ,总结的 10 条 Python 使用技巧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值