bytes,bytearray
基本概念
python3引入的两个新类型:
bytes: 不可变字节序列.
bytearray: 字节组,可变.
字符串与bytes:
字符串是字符组成的有序序列,字符可以使用编码来理解.
bytes是字节组成的有序的不可变序列.
bytearray是字节组成的有序的可变序列.
编码与解码:
字符串按照不同的字符集编码encode返回字节序列bytes.
encode(encoding='utf-8', errors='strict')-> bytes.
字节序列按照不同的字符集解码decode返回字符串.
bytes.decode(encoding='utf-8',errors='strict')-> str
bytearray.decode(encoding='utf-8',errors='strict')-> str
bytes定义
bytes() emptybytes.
bytes(int)指定字节的bytes,用0填充.
bytes(iterable_of_ints)-> bytes[0,255]的int组成的iterable对象.
bytes(string,encoding[,errors]) -> bytes等价于string.encode().
bytes(bytes_or_buffer)-> immutable copy of bytes_or_buffer 从一个字节序列或buffer中复制出一个新的不可变的bytes对象.
使用b前缀定义:
只允许基本ASCII使用形式b'abc9'.
使用16进制表示b'\x41\x61'.
bytes操作
和str类型类似,都是不可变类型,所以方法很多都一样,只是bytes的方法,输入和输出的都是bytes.
b'abcdef'.replace(b'f', b'k').
b'abc'.find(b'b')
类方法 bytes.fromhex(string)
string必须是2个字符的16进制的形式,'6162 6a 6b',空格将被忽略.
bytes.fromhex('6162 09 6a 6b00').
hex()
返回16进制表示的字符串.
'abc'.encode().hex()
索引:
b'abcdef'[2] 返回该字节对应的数,int类型.
bytearr定义
bytearray()空bytearray.
bytearray(int)指定字节的bytearray,被0填充.
bytearray(iterable_of_ints)-> bytearray[0,255]的int组成的iterable对象.
bytearray(string,encoding[,errors]) -> bytearray近似于string.encode(),不过返回可变对象.
bytearray(bytes_or_buffer)从一个字节序列或buffer中复制出一个新的可变的bytearray对象.
注: b前缀定义的类型是bytes类型.
bytearray操作
和bytes类型的方法相同
bytearray(b'abcdef').replace(b'f', b'k').
bytearray(b'abc').find(b'b')
类方法 bytearray.fromhex(string)
string必须是2个字符的16进制的形式,'6162 6a 6b',空格将被忽略.
bytearray.fromhex('6162 09 6a 6b00').
hex()
返回16进制表示的字符串.
bytearray('abc'.encode()).hex()
索引:
bytearray(b'abcdef')[2] # 返回该字节对应的数,int类型.
append(int)# 尾部追加一个元素.
insert(index,int) # 在指定索引位置插入元素.
extend(iterable_of_ints) # 将一个可迭代的整数集合追加到当前bytearray.
pop(index=-1) # 从指定索引上移除元素,默认从尾部移除.
remove(value) # 找到第一个value移除,找不到抛异常ValueError.
注: 上述方法若使用int类型,值在[0, 255].
clear() # 清空bytearray.
reverse() # 翻转bytearray,就地修改.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | In [1]: b = bytearray()
In [2]: b.append(97)
In [3]: b Out[3]: bytearray(b'a')
In [4]: b.decode() Out[4]: 'a'
In [5]: bytearray(range(97, 123)) Out[5]: bytearray(b'abcdefghijklmnopqrstuvwxyz')
In [6]: bytearray(range(97, 123)).decode() Out[6]: 'abcdefghijklmnopqrstuvwxyz'
In [7]: bytearray(range(65,91)).decode() Out[7]: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
In [8]: |
切片
线性结构
可迭代 for .. in
len()可以获取长度.
通过下标可以访问.
可以切片.
学过的线性结构: list, tuple, str, bytes,bytearray.
切片
通过索引区间访问线性结构的一段数据.
sequence[start:stop] # 表示返回[start, stop)区间的子序列.
支持负索引.
start为0,可以省略.
stop为末尾,可以省略.
start一定在stop的左边.
[:]表示从头至尾,全部元素被取出,等效于copy()方法.
步长切片: [start:stop:step]
step为步长,可以是正负整数,默认为1.
step要和start:stop同向,否则返回空序列.
1 2 3 4 5 6 7 8 9 10 11 12 15 16 17 18 | In [22]: bytearray(range(65, 90)).decode() Out[22]: 'ABCDEFGHIJKLMNOPQRSTUVWXY'
In [23]: bytearray(range(65, 90)).decode()[10:20] Out[23]: 'KLMNOPQRST'
In [24]: bytearray(range(65, 90)).decode()[10:20:3] Out[24]: 'KNQT'
In [25]: bytearray(range(65, 90)).decode()[-15:-5] Out[25]: 'KLMNOPQRST'
In [26]: bytearray(range(65, 90)).decode()[-15:-5:3] Out[26]: 'KNQT'
In [27]: |
封装和解构
封装
将多个值使用逗号分割,组合在一起.
本质上,返回一个元组,只是省略了小括号.
python特有语法,被很多语言学习和借鉴.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | In [6]: t1 = (1, 2)
In [7]: t2 = 1, 2
In [8]: t1 Out[8]: (1, 2)
In [9]: t2 Out[9]: (1, 2)
In [10]: type(t1) Out[10]: tuple
In [11]: type(t2) Out[11]: tuple
In [12]: |
举例:
1 2 3 4 5 6 7 8 9 10 11 12 13
| In [17]: a = 4
In [18]: b = 5
In [19]: temp = a
In [20]: a = b
In [21]: b = temp
# 或
In [22]: a, b = b, a # 等号右边使用了封装,左边使用了解构.
|
解构
把线性结构的元素解开,并顺序赋给其他变量.
左边接纳的变量数要和右边解开的元素个数一致.
1 2 3 4 5 6
| n [23]: lst = [3, 5]
In [24]: first, second = lst
In [25]: print(first, second) 3 5 |
举例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | In [28]: a, b = 1, 2
In [29]: a, b = (1, 2)
In [30]: a, b = [1, 2]
In [31]: a, b = {10, 20}
In [32]: a, b = {'a': 10, 'b': 20}
In [33]: a, b = {10, 20, 30} --------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-33-266c898e7d19> in <module>() ----> 1 a, b = {10, 20, 30}
ValueError: too many values to unpack (expected 2)
In [34]: a, *b = {10, 20, 30}
In [35]: [a, b] = (1, 2)
In [36]: [a, b] = 10, 20
In [37]: (a, b) = {30, 40}
In [38]: |
python3的解构
使用"*变量名"接收,但不能单独使用.
被"*变量名"收集后组成一个列表.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | In [6]: lst = list(range(1, 101, 2))
In [8]: head, *mid, tail = lst
In [9]: head Out[9]: 1
In [10]: tail Out[10]: 99
In [11]: *lst2 = lst File "<ipython-input-10-98211a44ccfb>", line 1 *lst2 = lst ^ SyntaxError: starred assignment target must be in a list or tuple
In [12]: *lst2 = lst File "<ipython-input-12-98211a44ccfb>", line 1 *lst2 = lst ^ SyntaxError: starred assignment target must be in a list or tuple
In [13]: *body, tail = lst
In [14]: tail Out[14]: 99
In [15]: head, *tail = lst
In [16]: head Out[16]: 1
In [17]: head, *m1, *m2, tail = lst File "<ipython-input-17-1fc1a52caa8e>", line 1 head, *m1, *m2, tail = lst ^ SyntaxError: two starred expressions in assignment
In [18]: head, *mid, tail = 'abcdefghijklmn'
In [19]: type(mid) Out[19]: list
In [20]: type(head) Out[20]: str
In [21]: |
丢弃变量
这是一个惯例,是一个不成文的约定,不是标准.
如果不关心一个变量,就可以定义修改变量的名字为下划线(_).
"_"是一个合法的标识符,也可以作为一个有效的变量使用,但是定义成下划线就是希望不要被使用,除非你明确的知道这个数据需要被使用.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | In [24]: lst = [9, 8, 7, 20]
In [25]: first, *second = lst
In [26]: head, *_, tail = lst
In [27]: head Out[27]: 9
In [28]: tail Out[28]: 20
In [29]: _ # 下划线是合法的标识符,看到下划线就知道这个变量不希望被使用. Out[29]: [8, 7]
In [30]: |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | In [32]: lst = [9, 8, 7, 20]
In [33]: first, *second = lst
In [34]: _, *_, tail = lst
In [35]: _ Out[35]: [8, 7]
In [36]: tail Out[36]: 20
In [37]: _ Out[37]: [8, 7] |
总结:
_这个变量本身无任何语义,没有任何可读性,所以不是用来给人使用的.
python中很多库,都使用这个变量,使用十分广泛,所以不要在不明确变量作用域的情况下,使用_导致和库中_冲突.
_, [*_, a], _ = lst # []或()都可以.
练习
集 – set
基本概念
约定:
set翻译为集合.
collections翻译为集合类型,是一个大概念.
set:
可变, 无序, 不重复的元素的集合.
定义,初始化
set() -> new empty set object.
set(iterable) -> new set object.
set的元素要求必须可hash.
目前学过的不可hash类型有list,set.
元素不可以索引.
set可迭代.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | In [41]: s2 = set(range(5))
In [42]: s3 = set(list(range(10)))
In [43]: s2 Out[43]: {0, 1, 2, 3, 4}
In [44]: s3 Out[44]: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
In [45]: s4 = {}
In [46]: type(s4) Out[46]: dict
In [47]: s5 = {9, 10, 11}
In [48]: s6 = {(1, 2), 3, 'a'}
In [49]: s7 = {[1], (1,), 1} --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-49-67713ab500d7> in <module>() ----> 1 s7 = {[1], (1,), 1}
TypeError: unhashable type: 'list' # set里面只能放置可哈希元素,list不可哈希,故报错.
In [50]: |
增加
add(elem)
增加一个元素到set中.
如果元素存在,什么也不做.
update(*others)
合并其他元素到set集合中来.
参数others必须是可迭代对象.
就地修改.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | In [64]: s1 = {1, 2, 3}
In [65]: s1.add('a')
In [66]: s1 Out[66]: {1, 2, 3, 'a'}
In [67]: s2 = {4, 5, 6}
In [68]: s3 = {7, 8, 9}
In [69]: s1.update(s2, s3)
In [70]: s1 Out[70]: {1, 2, 3, 4, 5, 6, 7, 8, 9, 'a'}
In [71]: |
删除
remove(elem)
从set中移除第一个元素.
元素不存在,抛出KeyError异常,因为set中的元素被hash过,类似dict中的key.
discard(elem)
从set中移除一个元素
元素不存在,什么都不做.
pop() -> item
移除并返回任意的元素.
空集返回KeyError异常.
clear()
移除所有元素.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | In [73]: s1 = {'one', 'two', 'three', 'four', 'five'}
In [74]: s1.remove('one')
In [75]: s1.remove('one') --------------------------------------------------------------------------- KeyError Traceback (most recent call last) <ipython-input-75-8a1942935899> in <module>() ----> 1 s1.remove('one')
KeyError: 'one'
In [76]: s1.discard('two')
In [77]: s1.discard('two')
In [78]: s1.pop() Out[78]: 'five'
In [79]: s1.pop() Out[79]: 'four'
In [80]: s1 Out[80]: {'three'}
In [81]: s1.clear()
In [82]: s1 Out[82]: set()
In [83]: |
修改,查询
修改:
要么删除,要么加入新的元素.
set元素不可重复,故没有修改方法.
查询:
非线性结构,无法索引.
遍历:
可以迭代所有元素.
成员运算符:
in和not in判断元素是否在set中.
效率高.
list和set关于成员运算符的比较: set要比list效率高.
set和线性结构
线性结构的查询时间复杂度是O(n), 即随着数据规模的增大而增加耗时.
set,dict等结构,内部使用hash值作为key,时间复杂度可以做到O(1),查询时间与数据规模无关.
可hash:
数值型: int,float,complex.
布尔型: True,False.
字符串: string, bytes.
tuple.
None.
以上都是不可变类型,成为可哈希类型,hashable.
集合运算
基本概念:
全集: 所有元素的集合.例如实数集,所有实数组成的集合就是全集.
子集(subset)和超集(superset): 集合A的所有元素在集合B中,A是B的子集,B是A的超集.
真子集和真超集: A是b的子集,且A不等于B,A就是B的真子集,B是A的真超集.
并集: 多个集合合并的结果.
交集: 多个集合的公共部分.
差集: 集合中除去和其他集合公共的部分.
并集:
union(*others) # 返回和多个集合合并后的新的集合.
"|"运算符重载: 等同于union.
update(*others): 和多个集合合并,就地修改.
"|=": 等同于update.
交集:
intersection(*others): 返回和多个集合的交集.
"&": 等同于intersection.
intersection_update(*others): 获取和多个集合的交集,并就地修改.
"&=": 等同于interse_update.
差集:
difference(*others): 返回和多个集合的差集.
"-": 等同于differenc.
difference_update(*others): 获取和多个集合的差集并就地修改.
"-=": 等同于difference_update.
对称差集:
symmetric_difference(other): 返回和另一个集合的差集.
"^": 等同于symmetric_difference.
symmetric_difference_update(other): 获取和另一个集合的差集并就地修改.
"^=": 等同于symmetric_difference_update.
issubset(other)和"<=": 判断当前集合是否是另一个集合的子集.
set1 < set2: 判断set1是否是set2的真子集.
issuperset(other)和">=": 判断当前集合是否是other的真超集.
set1 > set2: 判断set1是否是set的真超集.
isdisjoint(other): 判断当前集合和另一个集合有没有交集,没有交集返回True.
练习
字典 – dict
基本概念
key-value键值对的数据的集合.
可变,无序,key不重复.
定义,初始化
d = dict()或者d = {}
dict(**kwargs)使用name=value对初始化一个字典.
dict(iterable, **kwarg)使用可迭代对象和name=value对构造字典,不过可迭代对象的元素必须是一个二元结构.
d = dict(((1,'a'),(2,'b'))) or d = dict(([1,'a'],[2,'b']))
dict(mapping,**kwarg) 使用一个字典构建另一个字典.
d = {'a':10, 'b':20,'c':None,'d':[1,2,3]}
类方法 dict.fromkeys(iterable,value)
d = dict.fromkeys(range(5))
d = dict.fromkeys(range(5),0)
元素的访问
d[key]
返回key对应的值value.
key不存在则抛出异常KeyError.
get(key[,default])
返回key对应的值value.
key不存在返回缺省值,如果没有缺省值就返回None.
setdefault(key[,default])
返回key对应的值value.
key不存在则添加kv对,value为default,缺省值为None.
增加和修改元素
d[key] = value
将key对应的值修改为value.
key不存在则添加新的kv对.
update([other]) -> None
使用另一个字典的kv对更新本字典.
key不存在,就添加.
key存在,覆盖已存在的key对应的值.
就地修改.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | In [16]: d = {'a': 1, 'b': 2}
In [17]: d.update(red=1)
In [18]: d Out[18]: {'a': 1, 'b': 2, 'red': 1}
In [19]: d.update((('red', 2),))
In [20]: d Out[20]: {'a': 1, 'b': 2, 'red': 2}
In [21]: d.update({'red': 3})
In [22]: d Out[22]: {'a': 1, 'b': 2, 'red': 3}
In [23]: |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | In [31]: d = (('red', 2))
In [32]: d Out[32]: ('red', 2)
In [33]: dd = {'a': 1}
In [34]: dd.update(d) --------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-34-5fa4147f974f> in <module>() ----> 1 dd.update(d)
ValueError: dictionary update sequence element #0 has length 3; 2 is required
In [35]: d = (('red', 2),)
In [36]: d Out[36]: (('red', 2),)
In [37]: dd.update(d)
In [38]: dd Out[38]: {'a': 1, 'red': 2}
In [39]: |
删除元素
pop(key[,default])
key存在,移除它,并返回它的value.
key不存在,返回给定的default.
default未设置,key不存在则抛异常KeyError.
popitem()
移除并返回一个任意的键值对.
字典为empty,抛出异常KeyError.
clear()
清空字典.
字典删除
del语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | In [40]: a = True
In [41]: b = [6]
In [42]: d = {'a': 1, 'b': b, 'c': [1, 3, 5]}
In [43]: d Out[43]: {'a': 1, 'b': [6], 'c': [1, 3, 5]}
In [44]: del a
In [45]: a --------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-45-60b725f10c9c> in <module>() ----> 1 a
NameError: name 'a' is not defined
In [46]: del d['c']
In [47]: d Out[47]: {'a': 1, 'b': [6]}
In [48]: del b[0]
In [49]: b Out[49]: []
In [50]: c = b
In [51]: del c
In [52]: del b
In [53]: c --------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-53-2cd6ee2c70b0> in <module>() ----> 1 c
NameError: name 'c' is not defined
In [54]: b --------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-54-3b5d5c371295> in <module>() ----> 1 b
NameError: name 'b' is not defined
In [55]: b = d['b']
In [56]: b Out[56]: [] |
字典遍历
for … in dict
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | # 遍历key In [57]: d = {'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5}
In [58]: for k in d: ...: print(k) ...: one two four three five
In [59]: for k in d.keys(): ...: print(k) ...: one two four three five
In [60]:
# 遍历value In [60]: for k in d: ...: print(d[k]) ...: 1 2 4 3 5
In [61]: for k in d.keys(): ...: print(d.get(k)) ...: 1 2 4 3 5
In [62]: for v in d.values(): ...: print(v) ...: 1 2 4 3 5
In [63]:
# 遍历item,即kv对 In [64]: for item in d.items(): ...: print(item) ...: ('one', 1) ('two', 2) ('four', 4) ('three', 3) ('five', 5)
In [65]: for k,v in d.items(): ...: print(k,v) ...: one 1 two 2 four 4 three 3 five 5
In [66]:
|
总结:
python3中,keys,values,items方法返回一个类似与生成器的可迭代对象,不会把函数的返回结果复制到内存中.
python2中,上面的方法会返回一个新的列表,占据新的内存空间.
所以python2建议用iterkeys,itervalues,iteritems版本,返回一个迭代器,而不是一个copy.
字典的key
字典的key的要求和set的元素要求一致.
hashable可哈希才能作为key.
d = {1:0}
1 2 3 4 5 6 7 8 9 10 11 | In [67]: d = {1: 0, 2.0: 3, 'abc': None,('hello', 'world', 'python'):'string', b'abc': '135'}
In [68]: d Out[68]: {'abc': None, 1: 0, 2.0: 3, b'abc': '135', ('hello', 'world', 'python'): 'string'}
In [69]: |
工厂函数-defaultdict
defaultdict是Python内建dict类的一个子类.
用法: defaultdict(default_factory[,...]) --> dict with default factory.
第一个参数是default_factory,缺省是None,它提供一个初始化函数,可以是list,tuple,set和dict等.
它的其他功能与dict相同,当key不存在时,会调用这个工厂函数来生成key对应的value,即提供一个默认值,从而避免KeyError异常.
1 2 3 4 5
| >>> d = defaultdict(list) #default_factory是列表名称 >>> d['eric'] #访问一个不存在的键 [] #添加并返回默认值(一个空列表) >>> d defaultdict(<class 'list'>, {'eric': []}) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from collections import defaultdict d1 = {} d2 = defaultdict(list) for k in 'abcde': for v in range(5): if k not in d1.keys(): d1[k] = [] d1[k].append(v) print(d1)
for k in 'mnopq': for v in range(3): d2[k].append(v) print(d2) print(type(d2)) # <class 'collections.defaultdict'>
|
1 2 3 4 5 6 | from collections import defaultdict dic = defaultdict(set) for i in 'abcd': for j in range(1, 5): dic[i].add(j) print(dic) |
有序字典-OrderedDict
python中的字典是无序的,因为它是按照hash来存储的,但collections模块自带的子类OrderedDict则可以很好的解决这个问题.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # 使用OrderedDict前 In [1]: dic = {}
In [2]: dic['b'] = 2
In [3]: dic['a']= 1
In [4]: dic['c'] = 3
In [5]: dic Out[5]: {'a': 1, 'b': 2, 'c': 3}
# 使用OrderedDict方法 In [7]: from collections import OrderedDict
In [8]: dicc = OrderedDict()
In [9]: dicc['b'] = 2
In [10]: dicc['a'] = 1
In [11]: dicc['c'] = 3
In [12]: dicc Out[12]: OrderedDict([('b', 2), ('a', 1), ('c', 3)])
In [13]: |
总结:
有序字典可以记录元素插入的顺序,打印的时候也是按照这个顺序输出打印的.
3.6版本的python的字典就是记录key插入的顺序.