diff --git a/Chapter1/Chapter1.md b/Chapter1/Chapter1.md new file mode 100644 index 0000000..03712fb --- /dev/null +++ b/Chapter1/Chapter1.md @@ -0,0 +1,24 @@ +##第1章 数据结构和算法 + +##问题 +- 1.1 将序列分解为单独的变量 +- 1.2 从任意长度的可迭代对象中分解元素 +- 1.3 保存最后N个元素 +- 1.4 找到最大或最小的N个元素 +- 1.5 实现优先级队列 +- 1.6 在字典中将键映射到多个值上 +- 1.7 让字典保持有序 +- 1.8 与字典有关的计算问题 +- 1.9 在两个字典中寻找相同点 +- 1.10 从序列中移除重复项并保持元素间顺序不变 +- 1.11 对切片命名 +- 1.12 找出序列中出现次数最多的元素 +- 1.13 通过公共键对字典列表排序 +- 1.14 对不原生支持比较操作的对象排序 +- 1.15 根据字段将记录分组 +- 1.16 筛选序列中的元素 +- 1.17 从字典中提权子集 +- 1.18 将名称映射到序列的元素中 +- 1.19 同时对数据做转换和换算 +- 1.20 将对个映射合并为单个映射 + diff --git a/Chapter1/Chapter1.py b/Chapter1/Chapter1.py new file mode 100644 index 0000000..5b39427 --- /dev/null +++ b/Chapter1/Chapter1.py @@ -0,0 +1,477 @@ +#!/usr/bin/env python3 +#!encoding=utf-8 + + +def ch1_1(): + ''' + 1.1 将序列分解为单独的变量 + 对象可迭代,就可以分解,包括字符串,文件,迭代器,生成器 + 分解操作可以使用"_"来丢弃一些特定的值 + ''' + print("\nch1_1:") + data=['hello','ch1',["*","_"], (-6,1,4)] + + _,a,[_,b], (_,middle,_) = data + + print(a+b+str(middle)) #ch1_1 + + + +def ch1_2(): + ''' + 1.2 从任意长度的可迭代对象中分解元素 + "*表达式" 用于未知长度或者任意长度的对象分解 + 分解linux shadow文件字符串 + ''' + print("\nch1_2:") + + linux_shadow = "username:$1$jMzjGK//$Do9jjAM9TqHVhkH3eSytT.:14576:0:99999:7:::" + username,passwd,*drop = linux_shadow.split(":") + _, encrpty_type, encrpty_salt,encrptyed_str = passwd.split("$") + + print("type:%s\nsalt:%s\npasswd:%s\n" % (encrpty_type,encrpty_salt,encrptyed_str)) + + + +def ch1_3(): + ''' + 1.3 保存最后N个元素 + 使用colletions.deque + 添加,弹出均为O(1) + ''' + print("\nch1_3:") + + from collections import deque + + def search(lines, pattern, history=5): + pre_lines = deque(maxlen=history) #保存最后5个搜索结果 + for line in lines: + if pattern in line: + yield line, pre_lines + pre_lines.append(line) + + + with open('ch1_3.txt') as f: + for line, prelines in search(f, 'Java', 5): + print(prelines, len(prelines)) + print(line) + + +def ch1_4(): + ''' + 1.4 找到最大或者最小的N个元素 + 使用heapq中的nlargest和nsmallest + 找出学生成绩的前五名 + ''' + print("\nch1_4:") + + from heapq import nlargest,heapify,heappop + from operator import itemgetter + + #元素数量相对较小时使用nlargest nsmallest + dict1 = {'name1': 34, 'name2':45, 'name3': 98, 'name4':34, 'name5': 66, "name6":90, "name7":90} + top5 = nlargest(5, dict1.items(),key=lambda x:x[1]) #注意python3 iteritem没有了 用items替代了 + print(top5) + + + #如果元素总数很大,N很小 + heap = list(dict1.values()) #转化为list 变成堆 pop + heapify(heap) + for i in range(5): #输出最小的5个值 + print(heappop(heap)) + + #如果元素数量和N差不多大,建议排序再做切片 + for name,score in sorted(dict1.items(), key=itemgetter(1),reverse=True)[:5]: + print(name,score) + + +def ch1_5(): + ''' + 1.5 实现优先级队列 + 使用heapq来pop优先级最高的元素 + ''' + print("\nch1_5:") + + import heapq + + class PrioriyQueue: + def __init__(self): + self._queue=[] + self._index = 0 + def push(self, item, priority): + heapq.heappush(self._queue, [-priority,self._index,item]) #从高到低排列 + def pop(self): + return heapq.heappop(self._queue)[-1] + + q= PrioriyQueue() + q.push('1',1) + q.push('10',10) + q.push('100',100) + q.push('50',50) + q.push('double 50',50) + q.push('25',25) + + for i in range(5): + print(q.pop()) + + + +def ch1_6(): + ''' + 1.6 在字典中将键映射到多个值上 (一键多值字典) + 使用collections中的defaultdir + ''' + + print("\nch1_6:") + + from collections import defaultdict + d = defaultdict(list) + #一个键对应一个list + d['a'].append(1) + d['a'].append(2) + d['a'].append(3) + + d['b'].append(4) + + print(d) + + +def ch1_7(): + ''' + 1.7 让字典保持有序 + 使用collections中的OrderedDict类 + ''' + + print("\nch1_7:") + + from collections import OrderedDict + #OrderedDict 中维护了一个双向链接,来保持顺序加入的位置,大量数据会增大内存消耗 + d= OrderedDict() + d['1'] = 1 + d['2'] = 2 + d['3'] = 3 + d['4'] = 4 + + for key in d: + print(key,d[key]) + + +def ch1_8(): + ''' + 1.8 与字典有关的计算问题 如最小值,最大值,排序等 + 使用zip把字典的键值反过来 + ''' + print("\nch1_8:") + + scores = {'name1': 34, 'name2':45, 'name3': 98, 'name4':34, 'name5': 66, "name6":90, "name7":90} + + min_score = min(zip(scores.values(),scores.keys())) + max_score = max(zip(scores.values(),scores.keys())) + scores_sorted = sorted(zip(scores.values(), scores.keys()),reverse=True) + + print(min_score,max_score) + print(scores_sorted) + + +def ch1_9(): + ''' + 1.9 在两个字典中寻找相同点 + 寻找相同的键,相同的值等 + 使用集合操作 如 & - + ''' + + print("\nch1_9:") + + a={'x':1,'y':2,'z':3} + b={'w':100,'x':50,'y':2} + + print(a.keys() & b.keys()) + print(a.keys() - b.keys()) + print(a.items()& b.items()) + + + +def ch1_10(): + ''' + 1.10 从序列中移除重复项且保持元素间顺序不变 + 利用set和生成器,返回不同的元素 + ''' + print("\nch1_10:") + + def dedupe(items, key= None): + b = set() + for i in items: + val = i if key is None else key(i) + if val not in b: + yield i #生成器 + b.add(val) + + a=[{'x':1,'y':5},{'x':2,'y':7},{'x':1,'y':5},{'x':1,'y':100}] + + print(a) + + print( list(dedupe(a,key=lambda d:(d['x'],d['y']))) ) + + +def ch1_11(): + ''' + 1.11 对切片命名 + 避免在代码中存在硬编码的索引值,可以利用slice对切片命名 + ''' + print("\nch1_11:") + + items = [1,2,3,4,5,6,7,8,9] + + odd_slice = slice(0,9,2) + odd = items[odd_slice] + + print(odd_slice.start,odd_slice.stop,odd_slice.step) + print(odd) + + +def ch1_12(): + ''' + 1.12 找出序列中出现次数最多的元素 + 使用collections 中的Counter + ''' + + print("\nch1_12:") + + from collections import Counter + + scores_one = [99,89,87,76,98,76,89,92,89,67,59,78,98,92,90,85,56] + scores_two = [100,89,56,98,78,97,96,99,94,93,91,90] + + one_same_top_three = Counter(scores_one).most_common(3) + print(one_same_top_three) + + #Counter可以使用各种数学运算操作 + all_same_top_three = ( Counter(scores_one) + Counter(scores_two) ).most_common(3) + print(all_same_top_three) + + +def ch1_13(): + ''' + 1.13 通过公共键对字典列表排序 + 使用operator中的itemgetter得到字典的值 + ''' + + print("\nch1_13:") + + from operator import itemgetter + + rows = [ + {'fname':'A','lname':'B','uid': 1001}, + {'fname':'B','lname':'C','uid': 1003}, + {'fname':'E','lname':'D','uid': 1002}, + {'fname':'A','lname':'F','uid': 1010}, + ] + + rows_by_uid_and_fname =sorted(rows, key=itemgetter('uid','fname')) + + print(rows_by_uid_and_fname) + + #使用lambda 如果考虑性能使用itemgetter + rows_by_uid = sorted(rows, key=lambda s:s['uid'], reverse=True) + print(rows_by_uid) + + print( max(rows, key=itemgetter('uid')) ) + + +def ch1_14(): + ''' + 1.14 对不原生支持比较操作的对象排序 + sorted 传入key参数 + ''' + + print("\nch1_14:") + + from operator import attrgetter #属性提取 + + class User: + def __init__(self,user_id): + self.user_id = user_id + def __repr__(self): + return 'User({})'.format(self.user_id) + + users = [User(1),User(2),User(3),User(100)] + users_by_user_id= sorted(users, key=lambda s:s.user_id, reverse=True) + + print(users_by_user_id) + + users_by_user_id= sorted(users, key=attrgetter('user_id'), reverse=True) + print(users_by_user_id) + + print(max(users, key=attrgetter('user_id'))) + + +def ch1_15(): + ''' + 1.15 根据字段将记录分组 + 使用itertools.groupby + ''' + + print("\nch1_15:") + + from operator import itemgetter + from itertools import groupby + + rows = [ + {'cost': 190, 'date': '07/02/2016'}, + {'cost': 100, 'date':'07/01/2016'}, + {'cost': 10, 'date':'07/18/2016'}, + {'cost': 89, 'date':'07/10/2016'}, + {'cost': 78, 'date':'07/10/2016'}, + {'cost': 1000, 'date':'07/01/2016'} + ] + + #先按时间排序 + rows.sort(key=itemgetter('date')) + + #分组 + for date, items in groupby(rows,key=itemgetter('date')): + print(date) + for i in items: + print(i) + + #如果不排序,使用一键多值字典 + from collections import defaultdict + + dict = defaultdict(list) + for row in rows: + dict[row['date']].append(row) + print('\n defaultdict:') + print(dict['07/01/2016']) + + +def ch1_16(): + ''' + 1.16 筛选序列中的元素 + 使用列表推导式和生成器表达式,或者使用itemtools.compress + ''' + + print("\nch1_16:") + mylist=[1,4,-6,9,-7,-5,99,100,-1] + list1=[n for n in mylist if n > 0] + print(list1) + + list2=(n for n in mylist if n < 0) + for i in list2: + print(i) + + def is_int(val): + try: + x = int(val) + return True + except ValueError: + return False + mylist=['1','2','3','4','-','N/A','5'] + + list3 = list(filter(is_int, mylist)) + print(list3) + + numbers = [ + '1', + '2', + '3', + '4' + ] + + counts=[4,100,9,0] + + from itertools import compress + + more5 =[n > 5 for n in counts] + restult=list(compress(numbers, more5)) + print(restult) + +def ch1_17(): + ''' + 1.17 从字典中提取子集 + 利用字典推导式 + + ''' + + print("\nch1_17:") + prices = { + 'ACME': 45.23, + 'AAPL': 612.78, + 'IBM': 205.55 + } + + p1 = {key:value for key, value in prices.items() if value > 200} + print(p1) + + +def ch1_18(): + ''' + 1.18 将名称映射到序列的元素中 + 使用collections.namedtuple(命名元组) + 命名元组不可变,使用_replace替换元素 + ''' + + print("\nch1_18:") + + from collections import namedtuple + Subscriber = namedtuple('Subscriber',['addr','joined']) + sub = Subscriber('xxx@xx.com','2016-01-01') + print(sub, sub.addr, sub.joined) + + #替换字典的作用 + s = Subscriber('1@1.com','2016-01-02') + #命名元组不可变,使用_replace替换元素 + s = s._replace(addr='2@2.com') + print(s) + + +def ch1_19(): + ''' + 1.19 同时对数据做转换和换算 + ''' + + print("\nch1_19:") + + nums = [1,2,3,4,5] + s = sum(x*x for x in nums) + print(s) + + import os + files = os.listdir('.') + if any(name.endswith(".py") for name in files): + print('Yes') + else: + print('No') + + +def ch1_20(): + ''' + 1.20 将多个映射合并为单个映射 + 使用collections ChainMap解决 + ''' + + print("\nch1_20:") + + from collections import ChainMap + + a={'x':1,'z':3} + b={'y':2,'z':4} + + c = ChainMap(a,b) #使用原始的字典 + print(c['x'],c['y'],c['z']) + + print(list(c.keys()),list(c.values())) + + #用新建字典代替 + merged = dict(b) + merged.update(a) + print(merged['x'],merged['y'],merged['z']) + +def main(): + + for i in range(1,21): + func='ch1_%d()'%(i) + exec(func) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Chapter1/ch1_3.txt b/Chapter1/ch1_3.txt new file mode 100644 index 0000000..41219f9 --- /dev/null +++ b/Chapter1/ch1_3.txt @@ -0,0 +1,9 @@ +Perl +Python +PHP +C++ +Java +R +JavaScript +HTML +CSS diff --git a/Chapter2/Chapter2.md b/Chapter2/Chapter2.md new file mode 100644 index 0000000..1cf627a --- /dev/null +++ b/Chapter2/Chapter2.md @@ -0,0 +1,24 @@ +##第2章 字符串和文本 + + +##问题 +- 2.1 使用多个界定符分割字符串 +- 2.2 字符串开头或结尾匹配 +- 2.3 用Shell通配符匹配字符串 +- 2.4 字符串匹配和搜索 +- 2.5 字符串搜索和替换 +- 2.6 字符串忽略大小写的搜索替换 +- 2.7 最短匹配模式 +- 2.8 多行匹配模式 +- 2.9 将Unicode文本标准化 +- 2.10 在正则式中使用Unicode +- 2.11 删除字符串中不需要的字符 +- 2.12 审查清理文本字符串 +- 2.13 字符串对齐 +- 2.14 合并拼接字符串 +- 2.15 字符串中插入变量 +- 2.16 以指定列宽格式化字符串 +- 2.17 在字符串中处理html和xml +- 2.18 字符串令牌解析 +- 2.19 实现一个简单的递归下降分析器 +- 2.20 字节字符串上的字符串操作 \ No newline at end of file diff --git a/Chapter2/Chapter2.py b/Chapter2/Chapter2.py new file mode 100644 index 0000000..e775b54 --- /dev/null +++ b/Chapter2/Chapter2.py @@ -0,0 +1,172 @@ +#!/usr/bin/python3 +#encoding=utf8 + +def ch2_1(): + ''' + 2.1 使用多个界定符分割字符串 + 一个字符串中的分隔符不固定需要使用re.split开灵活切割字符串 + ''' + + print("\nch2_1:") + + import re + line = '我 是中国;人,你是-哪国人' + result = re.split(r'[ ;,-]\s*', line) + print(result) + + +def ch2_2(): + ''' + 2.2 在字符串的开头或者结尾处做文本匹配 + startswith和endswith + ''' + + print("\nch2_2:") + + import os + filenames = os.listdir(".") + md_file = [file for file in filenames if file.endswith((".md",".MD"))] + print(md_file) + + https = ["https:","HTTPS:"] + urls =["http://baidu.com","www.qq.com:80","https://github.com","ftp://mirror.aliyun.com"] + https_url = [url for url in urls if url.startswith(tuple(https))] + print(https_url) + + #使用正则 + import re + result=re.match(r"^(https:)","https://github.com") + if result: + print(result.groups()) + else: + print("no result") + + +def ch2_3(): + ''' + 2.3利用Shell通配符做字符串匹配 + 使用fnmatch模块中的fnmatch和fnmatchcase + ''' + + print("\nch2_3:") + + from fnmatch import fnmatch,fnmatchcase + + #fnmatch按照平台是否区分大小写,window不区分 + files = ["config.ini","data1.csv","data2.csv","ata_train.csv","README.md","CONTINUE.MD"] + print(files) + + data_file = [file for file in files if fnmatch(file,"data*.csv")] + print(data_file) + + #fnmatchcase 可以区分大小写 + print(files) + data_file = [file for file in files if fnmatchcase(file, "*.MD")] + print(data_file) + + +def ch2_4(): + ''' + 2.4 文本模式的匹配和查找 + 使用正则 + ''' + + print("\nch2_4:") + + text1 = "02/11/2017" + text2 = "02/11/2017 tomorrow is 02/12/2017" + + import re + if re.match(r"\d+/\d+/\d+", text1): + print("yes") + else: + print("no") + + date_p = re.compile(r"\d+/\d+/\d+") + if date_p.match(text1): + print("yes") + else: + print("no") + + result = date_p.findall(text2) + print(result) + + #增加捕获组 多次匹配或者查找,建议先编译 + date_p = re.compile(r"(\d+)/(\d+)/(\d+)") + result = date_p.findall(text2) + for month,day, year in result: + print("{}-{}-{}".format(year,month,day)) + + +def ch2_5(): + ''' + 2.5 对字符串中的文本做查找和替换 + + ''' + + print("\nch2_5:") + + text1 ="Today is 02/11/2017, 春节是02/26/2017" + + import re + + #先匹配,后替换 + result = re.sub(r"(\d+)/(\d+)/(\d+)",r"\3-\1-\2", text1) + print(result) + + data_p = re.compile(r"(\d+)/(\d+)/(\d+)") + + from calendar import month_abbr + + def change_date(m): + mon_name = month_abbr[int(m.group(1))] + return '{} {} {}'.format(m.group(2),mon_name,m.group(3)) + + result,count = data_p.subn(change_date, text1) + print("结果:",result, "\n总共替换:", count) + + + +def ch2_6(): + ''' + 2.6 以不区分大小写的方式对文本做检查和替换 + 使用re.IGNORECASE + ''' + print("\nch2_6:") + + text = "UPPER PYTHON, lower python, Mixed Python" + + import re + result = re.findall(r"python", text, flags=re.IGNORECASE) + print(result) + + #替换成相同的格式 + result = re.sub("python", "snake", text, flags=re.IGNORECASE) + print(result) #注意snake是全部小写 + + def matchcase(word): + def replace(m): + text = m.group() + if text.isupper(): + return word.upper() + elif text.islower(): + return word.lower() + elif text[0].isupper(): + return word.capitalize() + else: + return word + return replace + + result = re.sub("python", matchcase("snake"), text, flags=re.IGNORECASE) + print(result) + + +def main(): + + for i in range(1,7): + func='ch2_%d()'%(i) + exec(func) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/README.md b/README.md index 00b0041..2551944 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,25 @@ -python-cookbook -=============== +## python-cookbook 第三版 -Code samples from the "Python Cookbook, 3rd Edition", published by O'Reilly & Associates, May, 2013. \ No newline at end of file + +## 目录 +- [第1章 数据结构和算法](Chapter1/) +- [第2章 字符串和文本](Chapter2/) +- 第3章 数字,日期和时间 +- 第4章 迭代器和生成器 +- 第5章 文件和I/O +- 第6章 数据编码与处理 +- 第7章 函数 +- 第8章 类与对象 +- 第9章 元编程 +- 第10章 模块与包 +- 第11章 网络和Web编程 +- 第12章 并发 +- 第13章 实用脚本和系统管理 +- 第14章 测试,调试以及异常 +- 第15章 C语言扩展 + + + + +## 注意 +代码使用Python3 diff --git "a/\343\200\212Python Cookbook\343\200\213\347\254\254\344\270\211\347\211\210\344\270\255\346\226\207v2.0.0.pdf" "b/\343\200\212Python Cookbook\343\200\213\347\254\254\344\270\211\347\211\210\344\270\255\346\226\207v2.0.0.pdf" new file mode 100644 index 0000000..97fa4a5 Binary files /dev/null and "b/\343\200\212Python Cookbook\343\200\213\347\254\254\344\270\211\347\211\210\344\270\255\346\226\207v2.0.0.pdf" differ