查看原文
其他

几个 Python“小伎俩” | 内附代码

CSDN 2020-02-25

The following article comes from NewBeeNLP Author 想要快点答辩的

来源 | NewBeeNLP(ID:gh_627b00c8dbd0) 

责编 | 夕颜 


写在前面


今天,我们一起回顾下Python Cookbook,全书是以问答对的形式展开,这是我很久之前看的笔记。Cookbook不算是入门书,更像是一本工具书,既然有基础了那就没必要一个个点去看,建议是需要用到那部分就把那块的知识点技巧翻一遍。下面大噶自己查漏补缺吧!


数据结构与算法


从任意长度的可迭代对象中分解元素


*表达式可以用来将一个含有N个元素的数据结构类型分解成所需的几部分。


1first, *middle, last = grades


例如grades保存了100个成绩数据而我们只关心首末两个成绩,就可以把中间的所有成绩保存到一个列表里面,如下:


保存最后N个元素


  • collection.deque(maxlen=N)创建了一个固定长度的队列,当有新记录加入而队列已满时会自动移除最老的那条记录。

  • 若不指定队列的大小,也就得到了一个无界限的队列;

  • deque支持从队列两端添加或弹出元素

1from collection import deque
2q = deque()
3q.append(1)
4q.append(2)
5q.append(3)
6q.appendleft(4)
7q.pop()
8q.popleft()


找到最大或最小的N个元素


  • heapq模块中有两个函数:nlargest()和nsmallest()

1import heapq
2
3nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
4print(heapq.nlargest(3, nums))
5out: [42, 37, 23]
6print(heapq.nsmallest(3,nums))
7out: [-4, 1, 2]


  • 这两个函数还可以接受一个参数key

1In [1]: portfolio = [
2   ...: {'name''IBM''shares'100'price'91.1},
3   ...: {'name''AAPL''shares'50'price'543.22},
4   ...: {'name''FB''shares'200'price'21.09},
5   ...: {'name''HPQ''shares'35'price'31.75},
6   ...: {'name''YHOO''shares'45'price'16.35},
7   ...: {'name''ACME''shares'75'price'115.65}
8   ...: ]
9
10cheap = heapq.nsmallest(3, portfolio, key=lambda s: s['price'])
11cheap
12out:
13[{'name''YHOO''price'16.35'shares'45},
14 {'name''FB''price'21.09'shares'200},
15 {'name''HPQ''price'31.75'shares'35}]


让字典保持有序


  • collection模块的OrderedDict会按照元素初始添加的顺序进行操作;

  • 其内部维护了一个双向链表,它会根据元素加入的顺序来排列键的位置。因此OrderedDict的大小是普通字典的2倍多。


字典的计算问题


  • 利用zip()将字典的键与值反转


找出序列中出现次数最多的元素


  • collection模块的Counter类

  • 并且Counter类有一个非常方便的most_common(n)方法可以直接得到出现次数最多的前几位

1from collections import Counter
2words = [一系列单词组成的列表]
3word_counts = Counter(words)
4top_3 = word_counts.most_common(3)


通过公共键对字典列表排序

  • operator模块的itermgetter函数

1from operator import itemgetter
2
3In [26]: rows = [
4    ...: {'fname''Brian''lname''Jones''uid':1003},
5    ...: {'fname''David''lname''Beazley''uid':1002},
6    ...: {'fname''John''lname''Cleese''uid':1001},
7    ...: {'fname''Big''lname''Jones''uid':1004}
8    ...: ]
9
10itemgetter('fname')
11Out[31]: <operator.itemgetter at 0x7f01606657d0>
12
13rows_by_frame = sorted(rows, key=itemgetter('fname'))
14Out[30]:
15[{'fname''Big''lname''Jones''uid'1004},
16 {'fname''Brian''lname''Jones''uid'1003},
17 {'fname''David''lname''Beazley''uid'1002},
18 {'fname''John''lname''Cleese''uid'1001}]
  • itermgetter()函数还可以接受多个键

1rows_by_frame = sorted(rows, key=itemgetter('fname','lname'))


数字、日期和时间


对数值进行取整


  • 使用内建的round(value, ndigits)函数

1>>> round(1.231)
21.2
3>>> round(1.271)
41.3
5>>> round(162773, -1)
6162770


  • 当某个值恰好等于两个整数间的一半时,取整操作会去到离该值最近的那个偶数上。如1.5和2.5都会取整到2

  • round()中的ndigits可以是负数,在这种情况下会相应地取整到十位、百位。。。


对数值做格式化输出


  • 使用内建的format()函数

1>>>x = 123.456
2>>>format(x, '0.2f')
3123.46


二进制、八进制和十六进制转换


  • 要将一个整数转换为二进制,使用bin()

  • 要将一个整数转换为八进制,使用oct()

  • 要将一个整数转换为十六进制,使用hex()


随机选择


  • random.choice()可以从序列中随机挑选出元素

1>>>import random
2>>>values = [1,2,3,4,5,6]
3>>>random.choice(values)
44
5>>>random.choice(values)
62


  • random.shuffle()可以在序列中原地打乱元素的顺序


1>>>random.shuffle(values)
2>>>values
3[2,4,3,1,6,5]random.sample()可以取样出N个元素


  • random.sample()可以取样出N个元素

1>>>random.sample(values, 2)
2[6, 2]


时间换算


  • datatime模块可以用来完成不同时间单位间的换算。例如要表示一个时间间隔,可以创建一个timedelta实例

1from datetime import timedelta
2
3In [33]: a = timedelta(days=2, hours=6)
4In [34]: b = timedelta(hours=4.5)
5In [35]: c = a + b
6In [36]: c.days
7Out[36]: 2
8In [37]: c.seconds
9Out[37]: 37800
10In [38]: c.seconds/3600
11Out[38]: 10.5
12In [39]: c.total_seconds() / 3600
13Out[39]: 58.5


迭代器和生成器


手动访问迭代器中的元素


1with open('/etc/passwd'as f:
2    try:
3        while True:
4            line = next(f)
5            print(line, end='')
6    except StopIteration:
7        pass


委托迭代


  • 对自定义的容器对象,其内部持有一个列表丶元组或其他的可迭代对象,我们想让自己的新容器能够完成迭代操作。一般来说,我们所要做的就是定义一个__iter__()方法,将迭代请求委托到对象内部持有的容器上。

1class Node:
2    def __init__(self, value):
3        Self._value = vaule
4        self._children = []
5    def __repr__(self):
6        return 'Node({!r})'.format(self._value)
7    def __iter__(self):
8        return iter(self._children)


在这个例子中,iter()方法将迭代请求转发给对象内部持有的_children属性上。


用生成器创建新的迭代模式


  • 函数中只要出现了yield语句就会将其转变成一个生成器

1def frange(startstopincrement):
2    x = start
3    while x < stop:
4        yield x
5        x += increment


  • 注意生成器只在响应迭代操作时才运行


对迭代器做切片操作


  • itertool.islice() 可以对迭代器和生成器做切片操作

1In [3]: def count(n):
2   ...:     while True:
3   ...:         yield n
4   ...:         n += 1
5   ...:
6In [5]: c = count(0)
7In [6]: c
8Out[6]: <generator object count at 0x7f92899b3c80>
9----> 1 c[0]
10TypeError: 'generator' object has no attribute '__getitem__'
11
12import itertools
13In [10]: for x in itertools.islice(c, 1020):
14    ...:     print(x)
1510
1611
1712
1813
1914
2015
2116
2217
2318
2419


跳过可迭代对象中的前一部分元素


  • itertools.dropwhile() 函数会 丢弃掉序列中的前面几个元素
    例如,我们需要读取一个文件,文件的开头有一系列注释行并不是我们想要的

1from itertools import dropwhile
2with open('/etc/passwd'as f:
3    for line in dropwhile(lambda line: line,startwith('#'), f):
4        print(line, end='')


迭代所有可能的组合


  • 我们想对一些列元素的所有可能组合进行迭代

  • itrtools.permutations()函数接受一个元素集合,将其中所有元素重排列为所有可能的情况,并以元组的形式返回。

1In [11]: from itertools import permutations
2In [12]: items = ['a''b''c']
3In [13]: for p in permutations(items):
4    ...:     print(p)
5    ...:
6('a''b''c')
7('a''c''b')
8('b''a''c')
9('b''c''a')
10('c''a''b')
11('c''b''a')
#如果想得到较短的所有全排列,可以指定长度
In [14]: for p in permutations(items, 2):
   ...:     print(p)
('a', 'b')
('a', 'c')
('b', 'a')
('b', 'c')
('c', 'a')
('c', 'b')


  • itertools.combinations 不考虑元素间的实际顺序,即('a', 'b')和('b', 'a')被认为是相同的组合形式。

  • 若想解除这一限制,可用combinations_with_replacement。


同时迭代多个序列


  • zip()函数可以用来迭代多个序列中的元素

1>>>xvalues = [1,5,4,2,10,7]
2>>> yvalues = [101,78,37,15,62,99]
3>>> for x, y in zip(xvalues, yvalues):
4...     print(x, y)
5...
61 101
75 78
84 37
92 15
1010 62
117 99


在不同的容器中进行迭代


  • 我们需要对许多对象执行相同的操作,但是这些对象包含在不同的容器内,而我们希望可以避免写出嵌套的循环处理,保持代码的可读性。使用itertools.chain()方法可以用来简化这个任务。

1from itertools import chain
2
3In [18]: a = [1234]
4In [19]: b = ['x''y''z']
5In [20]: for x in chain(a, b):
6    ...:     print (x)
7    ...:
81
92
103
114
12x
13y
14z


合并多个有序序列,再对整个有序序列进行迭代


  • heapq.merge()函数

1>>>import heapq
2>>>a = [1,4,7,10]
3>>>b = [2,5,6,11]
4>>>for c in heapq.merge(a,b):
5...     print(c)
6...
71
82
94
105
116
127
1310
1411



文件和IO


将输出重定向到文件中


  • 只需要在print()函数加上file关键字参数即可

1with open('somefile.txt''rt'as f:
2    print('Hello World!', file=f)


以不同的分隔符或行结尾符完成打印

1>>>print('GKY',1995,5,18, sep='-',end='!!\n')
GKY-1995-5-18!!


在字符串上执行IO操作


  • 使用io.StringIO()和io.ByteIO()来创建类似于文件的对象,这些对象可操作字符串数据。


读写压缩的数据文件


  • gzip和bz2模块可以实现

1import gzip
2with open('somefile.gz''rt'as f:
3    text = f.read()
4
5import bz2
6with open('somefile.bz2''rt'as f:
7    text = f.read()
8
9import gzip
10with open('somefile.gz''wt'as f:
11    f.write(text)
12
13import bz2
14with open('somefile.bz''wt'as f:
15    f.write(text)


将二进制数据读到可变缓冲区中


  • 我们想将二进制数据直接读取到一个可变缓冲区中,中间不经过任何拷贝环节。例如我们想原地修改数据再将它写回到文件中去。

1import os.path
2def read_into_buffer(filename):
3    buf = bytearray(os.path.getsize(filename))
4    with open(filename, 'rb'as f:
5        f.readinto(buf)
6    return buf
7
8with open('sample.bin''wb'as f:
9    f.write(b'hello world')
10
11buf = read_into_buffer('sample.bin')
12In [16]: buf
13Out[16]: bytearray(b'hello world')


序列化Python对象


  • 我们需要将Python对象序列化为字节流,这样就可以将其保存到文件中、存储到数据库中或者通过网络连接进行传输。

  • 序列化数据最常见的做法就是使用pickle模块。

1import pickle
2data = ...  #some python object
3f = open('somefile''wb')
4pickle.dump(data,f)


  • 要将对象转存为字符串,可以使用

1import pickle
2data = ...  #some python object
3f = open('somefile''wb')
4pickle.dumps(data,f)


  • 如果要从字节流中重新创建出对象,可以使用pickle.load()或者pickle.loads()


数据编码与处理


读写JSON数据


  • 主要使用JSON模块

  • 两个主要的函数为json.dumps()和json.loads()

  • 如果是文件而不是字符串的话使用json.dump()和json.load()


解析简单的XML文档


  • xml.etree.ElementTree可以从简单的XML文档中提取数据

1from urllib.request import urlopen
2from xml.etree.ElementTree import parse
3
4u = urlopen('http://planet.python.org/rss20.xml')
5doc = parse(u)
6In [24]: for item in doc.iterfind('channel/item'):
7   ....:     title = item.findtext('title')
8   ....:     date = item.findtext('pubDate')
9   ....:     link = item.findtext('link')
10   ....:     print (title)
11   ....:     print(date)
12   ....:     print(link)
13   ....:     print()
14   ....:


【End】

技术战“疫”,贾扬清、李飞飞给程序员直播讲AI技术

2月18日、2月20日,阿里云CIO学院攻“疫”技术课程正式开启。您将获得与达摩院数据库首席科学家 、阿里巴巴集团副总裁、ACM 杰出科学家李飞飞,Caffe之父、ONNX创始人、阿里巴巴集团副总裁贾扬清,阿里巴巴集团副总裁、阿里 CIO 学院院长胡臣杰等顶级技术专家直播互动的机会。

推荐阅读 
工信部:短信可为 16 亿用户提供行程证明;OPPO 回应造芯计划;Windows Terminal 0.9 发布| 极客头条
 抗疫新举措,本周内你也能用上健康码!
几行代码构建全功能的对象检测模型,他是如何做到的?
疫情之下,哪些行业正在逆势爆发?
早期文献中的关系抽取论文整理,赶紧 Mark 起来!
一文读懂拜占庭将军问题
你点的每一个在看,我认真当成了喜欢
猛戳“阅读原文”,立即加入!

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存