读书笔记(5): 编写高质量python代码的59个有效方法

前言

《编写高质量python代码的59个有效方法》这本书分类逐条地介绍了编写python代码的有效思路和方法,对理解python和提高编程效率有一定的帮助。本笔记简要整理其中的重要方法。

承接上文https://www.jianshu.com/p/15a6050220e6
https://www.jianshu.com/p/1f6a2b3b502e
元类与属性 https://www.jianshu.com/p/1b1f3a0e87aa
并发及并行:https://www.jianshu.com/p/60ad9066d4b6

本篇介绍内置模块

6. 内置模块

用functools.wraps定义函数修饰器

Python用特殊的语法来表示修饰器,可以用来修饰函数,对于受到封装的原函数来说,修饰器能够在原函数执行之前及执行完毕之后,分别运行一些附加代码,使得开发者可以在修饰器中访问并修改原函数的参数及返回值,辅助调试等。

如下例,在递归函数中,利用修饰器trace将每次输入和输出打印出来:

def trace(func):
    def wrapper(*args,**kwargs):
        result=func(*args,**kwargs) # 执行原函数
        print('%s(%r,%r)->%r'%(func.__name__,args,kwargs,result)) # 打印我们要的信息
        return result  # 返回原函数的结果
    return wrapper
@trace
def fibonacci(n):
    if n in (0,1):
        return n
    return (fibonacci(n-2)+fibonacci(n-1))
# output
#fibonacci((0,),{})->0
#fibonacci((1,),{})->1
#fibonacci((2,),{})->1

但是加了修饰器后,原函数的一些特性在调用时发生改变:函数名称与原来名称不同,变成了修饰器内部函数的名称


使用functools中定义的wraps来对修饰器进行修饰即可,可以保证原函数的重要元数据都能被外界访问到:

from functools import wraps
def trace(func):
    @wraps
    def wrapper(*args,**kwargs):
        result=func(*args,**kwargs)
        print('%s(%r,%r)->%r'%(func.__name__,args,kwargs,result))
        return result
    return wrapper
@trace
def fibonacci(n):
    if n in (0,1):
        return n
    return (fibonacci(n-2)+fibonacci(n-1))

使用contextlib 和 with 语句改写可复用的try/finally代码

from threading import Lock

lock=Lock()
with lock:
    print('Hold the lock')
lock.acquire()
try:
    print('lock is held')
finally:
    lock.release()

Python提供了with语句来表达代码的运行时机。如上例所示,可以使用with的方式来进行操作,替代try/finally结构的代码。

我们可以使用内置的contextlib模块中的contextmanager修饰器,使用其修饰自己的函数,使得该函数支持with语句

使用datetime模块出来本地时间,而非time模块

UTC时间是一种标准的时间表示方式,与时区无关。对于计算机而言,UTC是一种非常好的计时方式,对人却不合适。需要将UTC和当地时间进行有效转换。

time模块中可以将UTC跟当地时间进行转换

from time import time,localtime,strftime,strptime,mktime
### 将时间戳转换成为字符串表示
now=time()
local=localtime(now)
time_str=strftime('%Y-%m-%d %H:%M:%S',local)
print(time_str) # 2020-09-16 19:59:34
time_tuple=strptime(time_str,'%Y-%m-%d %H:%M:%S')
utc_now=mktime(time_tuple)
print(utc_now) #1600257574.0

其中strftime、strptime可以实现将时间从时间戳转为标准格式的字符串或者反过来转为时间对象。这样地转换依赖于操作系统的时取配置信息,直接转为本地时取的时间信息。

datetime模块功能更加全面,可以转换成其他时区的时间

from datetime import datetime,timezone

now=datetime(2014,8,10,18,18,30)
now_utc=now.replace(tzinfo=timezone.utc)
now_local=now_utc.astimezone()
print(now_local)

同时datetime还具有timedelta等更由实用价值的时间计算工具,在编程中要多多使用。

使用内置算法与数据结构

python标准库中通用内置了大量数据结构和算法,不仅执行速度高,还能简化编程。

  1. 双向队列:deque 能够从队列头部/尾部插入或移除一个元素,只需消耗常数级别的时间。非常适合表示FIFO先进先出的队列
from collections import deque
fifo=deque()
fifo.append(1)
x=fifo.popleft()
fifo.appendleft(1)
fifo.appendleft(2)
y=fifo.pop()

list数据类型,当从头部插入或者移除元素时会消耗线性级别的时间,比较慢。

  1. 有序字典 OrderedDict
    默认的字典是无序的,当在键值相同的两个dict上迭代时,可能会出现不同的迭代顺序,主要是由于快速哈希表引起的
from collections import OrderedDict
a= OrderedDict()
 
a['1']=1
a['2']=3
a['0']=0
# (OrderedDict([('1', 1), ('2', 3), ('0', 0)])

OrderedDict可以根据键的插入顺序,保留键值对在字典中的次序

3. 带有默认值的字典

states={}
key='test'
if key not in states:
    states[key]=0

states[key]+=1

当我们用字典保存计数器信息时,需要如上的写法。我们可以用下面setdefault这种形式代替手工的查询判断。

states={}
key='test'
states.setdefault(key,0)
states[key]+=1
print(states)
key='test'
states.setdefault(key,0)
states[key]+=1
print(states)

也可使用defaultdict来简化

from collections import defaultdict
states=defaultdict(int)
key='test'
states[key]+=1

堆队列 headq

堆适合实现优先级队列,heaqp提供了heappush、heappop和nsmallest等一些函数,能够在标准的list类型之中创建堆结构

首先定义一个list,heappush可以将数据加入堆中,将list转换为堆结构;heappop能够每次从推中取出最小值。

from heapq import heappush,heappop

a=[]
heappush(a,5)
heappush(a,3)
heappush(a,7)
heappush(a,4)
print(heappop(a),heappop(a))

二分查找

from bisect import bisect_left
x=list(range(10*5))
i=x.index(100)
i=bisect_left(x,100)
print(i)

bisect模块中提供二分搜索方式,比线性的搜索算法更快。

6. 迭代器相关 itertools

itertools中提供大量函数,可以组合并操控迭代器,详细请自己查找相关资料

END

本人所有文章均为原创,欢迎转载,请注明文章出处 。百度和CSDN等站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的笔记/博文进行更新,因此请访问本人主页查看最新信息https://www.jianshu.com/u/40d14973d97c

你可能感兴趣的:(读书笔记(5): 编写高质量python代码的59个有效方法)