深入探究Python标准库—字典、集合、字符及字节序列

第一部分是字典的相关内容,比较详尽:

from collections import abc
import sys
import re
import collections
from types import MappingProxyType

my_dict = {}
result = isinstance(my_dict,abc.Mapping)	#检查my_dict 是否为dict类型(字典)
#print(result)
#作为字典的键,必须为可散列的数据类型(包括原子不可变数据类型str、bytes和数值类型还有frozenset)
a = dict(one=1,two=2)
b = {'one':1,'two':2}
c = dict(zip(['one','two'],[1,2]))
d = dict([('one',1),('two',2)])
e = dict({'two':2,'one':1})				#构造字典的五种方式
print(a==b==c==d==e)

#字典推导式,利用列表的迭代
name_tuu = [('zhangsan',1),('lisi',3),('wangwu',4),('huliu',9)]
name_dict = {num:name for name,num in name_tuu if num>=2 }
print(name_dict)

#映射方法
pot = name_dict.get(10,'Python can\'t find this key')	#default默认值处理找不到的键值对


WORD_RE = re.compile(r'\w+')
index = {}
with open(sys.argv[0],encoding='utf-8') as ff: #打开当前编辑文件
	for line_num,line in enumerate(ff):		#读取当前文件的每一行:行数+行内容
		for match in WORD_RE.finditer(line):		#读取每一字段的起止位置以及字段的文本内容
			word = match.group()			#每一字段的文本内容
			column_num = match.start() + 1	#每一字段的起始位置
			location = (line_num,column_num) #每一字段的行数和起始位置
			address = index.get(word,[])	#追踪word的位置,无则返回[]用于初始化
			address.append(location)		#在初始化的[]中添加位置location的元组
			index[word] = address			#修改index字典中键word的对应value值
#最后三行可替换为index.setdefault(word,[]).append(location)
for word in sorted(index,key=str.upper):
	print('{0:25s}'.format(word),":",index[word])

#映射的弹性键查询
a = collections.defaultdict(list)		#把list构造方法作为default_factory来创建一个defaultdict
a['word'].append((1024,101))
a['word'].append((1024,102))
a['animals']							#若查询不到对应键值,则为其创造一个空的列表值,append()函数可为其添加值
print(a)
#特殊方法__missing__()与上述基本一致,当查询的数据类型不一致时可以转换,以再给一次查询机会

#不可变映射类型mappingproxy,但可以修改原映射
d = {1:'A'}
d_proxy = MappingProxyType(d)
try:
	d_proxy[2] = 'B'
except:
	print('TypeError')
d[2] = 'S'
print(d_proxy)		#d_proxy是动态的,对d所作的修改会反馈到其身上 

第二部分是集合的相关内容:

from icecream import ic
from dis import dis
from unicodedata import name

'''set:许多唯一对象的聚集,可用于去重'''
list_1 = ['red','blue','black','blue','red']
set_1 = set(list_1)		#建立唯一集合
set_2 = {'green','red','black'}
count = len(set_1 & set_2)	#计算两集合的交集,即set_1的元素在set_2中出现的次数
count_co = len((set_1).intersection(set_2))	#上式的另一种写法
ic(count_co)

#两种构造方法
dis('{1,2,3}')			#这种更快的返回集合,字面量句法
dis('set([1,2,3])')		#构造函数方法偏慢

set_frozen = frozenset(range(4)) #frozenset的标准字符串的构造方法

#集合推导式,同列表,符号换为{}
set_build = {chr(i) for i in range(32,256) if 'SIGN' in name(chr(i),'')}
ic(set_build | set_1)		#求并集
ic(set_build > set_1)		#求前者是否为后者的真父集 
ic(hash(1))
assert set_1 != set_2

第三部分是字符和字节序列的相关内容:

#字符、码位和字节表述

#bytes、bytearray、memoryview等二进制序列的独特性

#全部Unicode和陈旧字符集的编解码器

#避免和处理编码错误

#处理文本文件的最佳实践

#默认编码的陷阱和标准I/O的问题

#规范化Unicode文本,进行安全的比较

#规范化、大小写折叠和暴力移除音调符号的使用函数

#使用locale模块和PyUCA库正确的排序Unicode文本

#Unicode数据库中的字符元数据

#能处理字符串和字节序列的双模式
上述为研究大纲,

from icecream import ic
from dis import dis
from array import array
import struct,sys,locale,os
from unicodedata import normalize,name
import unicodedata,pyuca,re

#①字符、码位和字节表述
word = 'cafe'			#字符的最佳定义为‘Unicode’字符
word_en = word.encode(encoding='utf-16')		#编码为UTF-16LE码型,bytes类型
ic(len(word),len(word_en),type(word_en))		
ic(type(word_en.decode('utf-16')))		#以UTF-16LE解码为str对象

#②bytes、bytearray、memoryview等二进制序列的独特性,可用struct模块来进行转换
cafe = bytes('cafe',encoding='utf-8')	#含4个字节的bytes对象,各元素是介于0~255的整数
ic([cafe[i] for i in range(len(cafe))])		#返回其对应整数
ic(cafe[:])		#bytes对象切片还是bytes
cafe_arr = bytearray(cafe)		#bytearray对象类似bytes类型,但是无字面量语句,切片类型不变
ic(cafe_arr)		#示例,无字面量语句
numbers = array('h',[-2,-1,0,1,2])		#创建短整数(16位)数组
ic(bytes(numbers))		#组成numbers数组的字节序列

#memoryview提供了共享内存的机会
with open('example_0.gif','rb') as fn:
	img = memoryview(fn.read())
headers = img[:10]	#选取前十个字节
fmt = '<3s3sHH'		#结构体格式,两个三字节序列和两个16位二进制整数
ic(struct.unpack(fmt,headers))		#拆包memoryview对象,得到元组(类型,版本,宽度和高度)
del headers		#释放内存

#③全部Unicode和陈旧字符集的编解码器'latin-1,utf-8,utf-16,ascii,cp1252,cp437,gb2312'
for engine in ['latin-1','utf8','utf16','ascii','gb2312']:
	ic(engine,'EL Nine'.encode(engine))				#utf8为目前Web中最常见的八位编码,与ASCII兼容

#④避免和处理编码错误:UnicodeEncodeError与UnicodeDecodeError、SyntexError
city = 'Sãa Paulo'
#city.encode('cp437') #将出现UnicodeEncodeError,解决办法如下:
ic(city.encode('cp437',errors='replace')) 		#把无法编码的字符换成  :?
ic(city.encode('cp437',errors='xmlcharrefreplace'))	#把无法编码的字符替换为XML实体

octets = b'Montr\xe9al'		#使用utf_8将会产生UnicodeDecodeError错误
ic(octets.decode('utf8',errors='replace'))		#把无法解码的字节换成  :�

#鬼符:BOM
ic(city.encode('utf16'))		#b'\xff\xfe'指明编码时使用Intel CPU的小字节序
a = city.encode('utf16')
ic(list(a))		#各码位的最低有效字节在前面,例S:83,0.而大字节序相反:0,83
b = city.encode('utf-16be')	#大字节序
c = city.encode('utf-16le')	#小字节序
ic(list(b),list(c))			#有许多windows软件根据BOM来确定解码方式,内容繁杂不一一介绍

#⑤处理文本文件的最佳实践:‘Unicode三明治’
'''一、尽早把输入解码为字符串
二、业务只处理字符串对象
三、输出尽量晚的编码为字节序列'''
with open('example_0.txt','w',encoding='utf-8') as fn:
	fn.write('what are you watching�')
with open('example_0.txt','r',encoding='utf-8') as ff:
	ic(ff.read())
fp = open('example_0.txt')
ic(fp)			#显示了默认解码方式‘cp936’,因此打开文本文件时一定要著明解码方式

#⑥默认编码的陷阱和标准I/O的问题
expressions = '''
locale.getpreferredencoding()		
type(my_file)
my_file.encoding
sys.stdout.isatty()
sys.stdout.encoding
sys.stdin.isatty()
sys.stdin.encoding
sys.stderr.isatty()
sys.stderr.encoding
sys.getdefaultencoding()
sys.getfilesystemencoding()
''' #最后一项用于解码文件名字,第一项用于解码文件内容的默认编解码方式

my_file = open('example_0.txt','w')

for expression in expressions.split():
	value = eval(expression)
	print(expression.rjust(30),'->',repr(value))

#⑦规范化Unicode文本,进行安全的比较
s1 = 'cafe\u0301' 	#é和e\u0301为标准等价物
s2 = 'café'
ic(s1,s2,len(s1),len(s2),s1==s2)

ic(len(normalize('NFC',s1)),len(normalize('NFD',s1))) #NFC:使用最少的码位构成等价的字符串,NFD:最多的码位

ohm = '\u2126'
ic(ohm)
ic(normalize('NFC',ohm),normalize('NFC',ohm)==ohm)	#注意某些单字符会被规范成另一种字符

half = '\u00bd'
ic(half,normalize('NFKC',half))	#兼容分解
micro = '\u00b5'
ic(micro,normalize('NFKC',micro),micro==normalize('NFKC',micro))	#得到小写字母'\u03bc'

#⑧规范化、大小写折叠和暴力移除音调符号的实用函数
#大小写折叠即全部转为小写,与str.casefold()和str.lower()相同
ic(name(micro),name(micro.casefold()),micro.casefold())
#自由定义规范化实用函数:
def nfc_equal(str_1,str_2):		#判断是否为规范化后一致
	return normalize('NFC',str_1) == normalize('NFC',str_2)
def fold_equal(str_1,str_2):	#判断是否规范化后大小写折叠一致
	return (normalize('NFC',str_1)).casefold() == (normalize('NFC',str_2)).casefold()
def shave_mark(txt): 			#去掉音调符号
	norm_txt = normalize('NFD',txt)		#分离音调和字符
	shaved = ''.join(i for i in norm_txt if not unicodedata.combining(i))
	return normalize('NFC',shaved)
ic(shave_mark(s2))
#另一个规范对象是拉丁语系,区别就是忽略拉丁基字符的变音符号,不详谈
#⑨使用locale模块和PyUCA库正确的排序Unicode文本
locale.setlocale(locale.LC_COLLATE,'pt_BR.UTF-8')		#为应用设置合适的区域设置
fruits = ['caju','atemoia','cajé','acerola']			
ic(sorted(fruits,key=locale.strxfrm))		#排序时将忽略音调符号,即视café为cafe
ic(sorted(fruits,key=pyuca.Collator().sort_key))		#使用Unicode排序算法进行排序

#⑩Unicode数据库中的字符元数据
re_digit = re.compile(r'\d')
sample = '1\xbc\xb2\u0969\u136b\u216b\u2466\u2480\u3285'

for char in sample:
 	print('U+%04x' % ord(char),#U+0000式的码位
 		char.center(6),			#在长度为6的字符串中居中显示
 		're_dig' if re_digit.match(char) else '-',	#匹配r'\d'
 		'isdig' if char.isdigit() else '-',			
 		'isnum' if char.isnumeric() else '-',
 		format(unicodedata.numeric(char),'5.2f'),	#长度为5,小数2位
 		unicodedata.name(char),		#Unicodedata中字符的名称
 		sep='\t')

#⑩①能处理字符串和字节序列的双模式
#os函数中的字符串和字节序列
ic(os.listdir('.'),os.listdir(b'.'))		#第二个返回字节序列
ic([os.fsdecode(i) for i in os.listdir(b'.')])		#返回解码类型
ic([os.fsencode(i) for i in os.listdir('.')])		#返回编码类型



内容参考《流畅的Python》一书。敬请批评指正

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值