这篇博客主要是阅读python之旅 时做的笔记。提取出最主要的知识点,供个人在以后中快速查阅。
下面是该书的主要脉络。
基础
字符编码
ASCII,Unicode以及UTF-8是较为常用的三种字符编码。
简单来说ASCII占一个字符,只规定了128个字符,但是Unicode是四个字节的,如果表示某些只要一个字节的字符,显然就浪费存储空间。因此在Unicode的基础上,人们开发出了UTF-16,UTF-32和UTF-8。
UTF-8是用一个字节到四个字节来表示字符。 在UTF-8中,ASCII字符仍旧用一个字节表示,阿拉伯文、希腊文等使用两个字符表示,常用汉字用三个字符表示。
python的默认编码
- python2:ASCII
>>> import sys
>>> sys.getdefaultencoding()
'ascii'
- python3: UTF-8
>>> import sys
>>> sys.getdefaultencoding()
'utf-8'
python2的字符类型
简单来说python2有两种字符串类型,str和unicode,两种类型可以用decode和encode相互转换。Unicode类型的字符串定义前面加个u,比如 u’小兵’
>>> '中文'.decode('utf-8')
u'\u4e2d\u6587'
>>> u'中文'.encode('utf-8')
'\xe4\xb8\xad\xe6\x96\x87'
UnicodeEncodeError & UnicodeDecodeError 根源
用 Python2 编写程序的时候经常会遇到 UnicodeEncodeError 和 UnicodeDecodeError,它们出现的根源就是如果代码里面混合使用了 str 类型和 unicode 类型的字符串,Python 会默认使用 ascii 编码尝试对 unicode 类型的字符串编码 (encode),或对 str 类型的字符串解码 (decode),这时就很可能出现上述错误。
- 在进行同时包含str 类型和 unicode 类型的字符串操作时,Python2 一律都把 str 解码(decode)成 unicode 再运算,这时就很容易出现 UnicodeDecodeError。
解决方法是直接用指定’utf-8’编码,
>>> s = '你好' # str 类型,utf-8 编码
>>> u = u'世界'
>>>
>>> s.decode('utf-8') + u # 显示指定 'utf-8' 进行转换
u'\u4f60\u597d\u4e16\u754c' # 注意这不是错误,这是 unicode 字符串
- 如果函数或类等对象接收的是 str 类型的字符串,但你传的是 unicode,Python2 会默认使用 ascii 将其编码成 str 类型再运算,这时就很容易出现 UnicodeEncodeError。
raw_input
raw_input只接受str类型的字符串
>>> name = raw_input('输入你的姓名:')
输入你的姓名: 小明
>>> name
'\xe5\xb0\x8f\xe6\x98\x8e'
>>> type(name)
<type 'str'>
怎样让输入的字符串变成Unicode的呢?
>>> name = raw_input(u'输入你的姓名: '.encode('utf-8')).decode('utf-8') # 推荐
输入你的姓名: 小明
>>> name
u'\u5c0f\u660e'
>>> type(name)
<type 'unicode'>
输入
Python2 提供了 input,raw_input,print 等用于输入输出,但在 Python3 中发生了一些改变,raw_input 已经没有了,input 的用法发生了变化,print 也从原来的语句变成了一个函数。本文将对这两种情况进行介绍。
python2
废话不多说,一句话raw_input就是将所有的输入都转换成一个字符串。
而如果用input的话,输入数字就是数字的类型,输入字符串得用’ ‘啊啊啊。
python3
python3中的input就是python2的raw_input,当然想要用python2的input就得这样
eval(input()),就是将字符串str当成有效的表达式来求值并返回计算结果
输出
python2中,print时可加可不加括号。python3中就一定得加括号。
格式化输出
>>> s = 'hello'
>>> l = len(s)
>>> print('the length of %s is %d' % (s, l))
the length of hello is 5
>>>
>>> pi = 3.14159
>>> print('%10.3f' % pi) # 字段宽度 10,精度 3
3.142
>>> print('%010.3f' % pi) # 用 0 填充空白
000003.142
>>> print('%+f' % pi) # 显示正负号
+3.141590
换行输出
print 默认是换行输出的,如果不想换行,可以在末尾加上一个 `,’,比如:
>>> for i in range(0, 3):
... print i
...
0
1
2
>>> for i in range(0, 3):
... print i, # 加了 ,
...
0 1 2 # 注意会加上一个空格
常用数据类型
总说
一般来说总说很重要。。
简单来说python中主要有5种数据类型。当然咯,就是 列表,元组,字符串,字典和集合。
序列类型: 列表、元组、字符串
其他类型:字典和集合
其实就是一句话:只要是序列就有公共的通用操作:
- 索引
- 分片
- 迭代
- 加
- 乘
- 检查某元素是否属于序列的成员,计算序列长度等等
列表定义用[ ],字符串用’ ‘,元组用()
字符串和元组是不可变的,可变的只有列表!
索引
python是从0开始的,然后用负数表示倒数。比如-1表示倒数第一个。
>>> nums = ['a', 2, 3, 4, 5] # 列表
>>> nums[0]
'a'
>>> nums[-1]
5
分片
这个就是切切切,当然要制定切的左端和右端,最重要的一点是左闭右开,所以都是用正数表示的切的位置,直接大减小就是切出的序列的长度。
>>> numbers = [1, 2, 3, 4, 5, 6]
>>> numbers[-3:-1] # 实际取出的是 numbers[-3], numbers[-2]
[4, 5]
>>> numbers[-3:0] # 左边索引的元素比右边索引出现得晚,返回空序列
[]
>>> numbers = [1, 2, 3, 4, 5, 6, 7, 8]
>>> numbers[-3:]
[6, 7, 8]
>>> numbers[5:]
[6, 7, 8]
# [:]可以复制整个序列
分片的其他知识
- 使用步长
left_idx: right_idx: step
左边比右边小。
当然仍旧是左闭右开,如果是step为负数,则是从右边往左边取,此时是左边大右边小。
比如
>>> numbers = [1, 2, 3, 4, 5, 6, 7, 8]
>>> numbers[4:0:-1] # 取出索引为 4, 3, 2, 1 的元素,仍就是左闭右开。
[5, 4, 3, 2]
加
这个有啥好说的啊,就是往序列中添加元素呗。直接“+”不就行了。
乘
乘N就是加N次。
>>> [1, 2, 3] * 3
[1, 2, 3, 1, 2, 3, 1, 2, 3]
>>>'hehe'*3
'hehehehehehe'
in
检查某个值是否在序列中。
>>>'he' in 'hehh'
True
列表
上面既然已经说了序列的通用操作,那么就说说针对列表有哪些常用的函数吧
- index
- count
- append
- extend
- insert
- pop
- remove
- reverse
- sort
index:就是看某个元素的索引呗。且只返回第一个该元素的索引,稍微想想也知道啊,不可能给你一大堆索引的吧,所以就返回第一个得了。
>>> words = ['hello', 'world', 'you', 'me', 'he','meagain']
>>> words.index('me')
3
count:略吧
append:末尾增加新的元素,由于list的元素类型可以是任意的,所以你可以随便append啊
>>>a = ['a',1,2]
>>>a.append(['what',1])
['a', 1, 2, ['what', 1]]
extend: (⊙v⊙)嗯,扩展,想必也是类似append,但是发现没有,扩展并不是添加,所以它是:
将一个新列表的元素添加到原列表中
>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> a.extend(b)
>>> a
[1, 2, 3, 4, 5, 6]
insert: insert(pos, value) 是将value添加到pos的位置。
pop:默认是移除最后一个,也可以移除指定index的元素。list.pop()或是list.pop(index)
remove:list.remove(‘value’), 只移除第一个匹配的
reverse:反转
显然像这些extend,append,insert, pop, reverse, remove等都是在原序列上进行操作的。
sort是返回新的列表。默认从小到大升序排列。 list.sort(reverse=True)就降序了。
sorted就是在原列表上进行操作
你可能会觉得,啊啊,那我要进行制定方式进行排序呢。加key!
>>> s = ['ccc', 'a', 'bb', 'dddd']
>>> s.sort(key=len) # 使用 len 作为键函数,根据元素长度排序
>>> s
['a', 'bb', 'ccc', 'dddd']
字符串
显然,满足通用的序列操作。再次强调,只有列表可变啊啊啊!字符串是不可变的。所以不能给字符串赋值。
常用字符串方法
- find
- split
- join
- strip
- replace
- translate
- lower/upper
find: 查找子串呗。没找到就返回-1
>>> motto = "to be or not to be, that is a question"
>>> motto.find('be') # 返回 'b' 所在的位置,即 3
3
>>> motto.find('be', 4) # 指定从起始位置开始找,找到的是第 2 个 'be'
16
>>> motto.find('be', 4, 7) # 指定起始位置和终点位置,没有找到,返回 -1
-1
split: 字符串切成序列
这个有意思啊,相当于字符串往列表转,而且可以指定切的分隔符。
显然默认空格作为分隔符啊
>>> '/user/bin/ssh'.split('/') # 使用 '/' 作为分隔符
['', 'user', 'bin', 'ssh']
>>> '1+2+3+4+5'.split('+') # 使用 '+' 作为分隔符
['1', '2', '3', '4', '5']
>>> 'that is a question'.split() # 没有提供分割符,默认使用所有空格作为分隔符
['that', 'is', 'a', 'question']
join: 可以说是split的逆方法吧
>>> '/'.join(['', 'user', 'bin', 'ssh'])
'/user/bin/ssh'
>>>
>>> '+'.join(['1', '2', '3', '4', '5'])
'1+2+3+4+5'
>>> ' '.join(['that', 'is', 'a', 'question'])
'that is a question'
>>> ''.join(['h', 'e', 'll', 'o'])
'hello'
strip:去掉字符串左右两边的空格,或是指定的字符串
>>> ' hello world! '.strip() # 移除左右两侧空格
'hello world!'
>>> '%%% hello world!!! ####'.strip('%#') # 移除左右两侧的 '%' 或 '#'
' hello world!!! '
>>> '%%% hello world!!! ####'.strip('%# ') # 移除左右两侧的 '%' 或 '#' 或空格
'hello world!!!'
replace: 替换所有
>>> motto = 'To be or not To be, that is a question'
>>> motto.replace('To', 'to') # 用 'to' 替换所有的 'To',返回了一个新的字符串
'to be or not to be, that is a question'
>>> motto # 原字符串保持不变
'To be or not To be, that is a question'
translate: 看名称就知道了啊,翻译翻译,当然是一个字一个字对应的。所以要用指定的翻译对应表,这开始有点扯了。
>>> from string import maketrans
>>> table = maketrans('aeiou', '12345')
>>> motto = 'to be or not to be, that is a question'
>>> motto.translate(table)
't4 b2 4r n4t t4 b2, th1t 3s 1 q52st34n'
>>> motto
'to be or not to be, that is a question'
>>> motto.translate(table, 'rqu') # 移除所有的 'r', 'q', 'u'
't4 b2 4 n4t t4 b2, th1t 3s 1 2st34n'
lower/upper: 略
元组
不可变序列,用圆括号表示。
>>> a = (1, 2, 3) # a 是一个元组
>>> a
(1, 2, 3)
>>> a[0] = 6 # 元组是不可变的,不能对它进行赋值操作
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
一个值的元组
创建一个值的元组需要在值后面再加一个逗号,这个比较特殊,需要牢牢记住:
>>> a = (12,) # 在值后面再加一个逗号
>>> a
(12,)
>>> type(a)
<type 'tuple'>
>>>
>>> b = (12) # 只是使用括号括起来,而没有加逗号,不是元组,本质上是 b = 12
>>> b
12
>>> type(b)
<type 'int'>
想想也是啊,因为元组是用圆括号定义的啊,如果只有一个值的话,那么不加逗号不就成为了数了啊。
元组不可变,所以没有append,extend,sort等方法。
字典
总说:字典是映射类型,有key和value构成,显然key要求是不可变类型,所以只能是数字,字符串和元组。
字典的三种基本操作
- 创建字典
用{ }, 讲完。哈哈,开玩笑的。
>>> d1 = {'name': 'ethan', 'age': 20}
>>> d1
{'age': 20, 'name': 'ethan'}
>>> d1['age'] = 21 # 更新字典
>>> d1
- 基本遍历
for key in dict 结构
for key in d:
print '%s: %s' % (key,d[key])
另一种遍历,如果遍历时要删除字典的某一项,那么要改改遍历方法:
for key in d.keys(): # python3的时候改成list(d.keys())
if key == 'name'
del d[key]
- 推荐的遍历方法
使用iteritems函数。
for k,v in d.iteritems():
print '%s: %s' % (k,v)
- 判断键是否在字典
一样的啊,用in呗。
字典的常用方法
- clear
- copy
- get
- setdefault
- update
- pop
- popitem
- keys/iterkeys
- values/iteritems
- fromkeys
clear:
>>> d1 = {}
>>> d2 = d1
>>> d2['name'] = 'ethan'
>>> d1
{'name': 'ethan'}
>>> d2
{'name': 'ethan'}
>>> d1.clear() # d1 清空之后,d2 也为空
>>> d1
{}
>>> d2
{}
copy
copy: 这个比较特殊诡异。竟然是浅复制。。
copy 方法实现的是浅复制(shallow copy)。它具有以下特点:
- 对可变对象的修改保持同步;
- 对不可变对象的修改保持独立 ;
# name 的值是不可变对象,books 的值是可变对象,再读一遍,是看“值”是什么类型!!
>>> d1 = {'name': 'ethan', 'books': ['book1', 'book2', 'book3']}
>>> d2 = d1.copy()
>>> d2['name'] = 'peter' # d2 对不可变对象的修改不会改变 d1
>>> d2
{'books': ['book1', 'book2', 'book3'], 'name': 'peter'}
>>> d1
{'books': ['book1', 'book2', 'book3'], 'name': 'ethan'}
>>> d2['books'].remove('book2') # d2 对可变对象的修改会影响 d1
>>> d2
{'books': ['book1', 'book3'], 'name': 'peter'}
>>> d1
{'books': ['book1', 'book3'], 'name': 'ethan'}
>>> d1['books'].remove('book3') # d1 对可变对象的修改会影响 d2
>>> d1
{'books': ['book1'], 'name': 'ethan'}
>>> d2
{'books': ['book1'], 'name': 'peter'}
深复制就用copy模块的deepcopy。
get
get: 就是防止你随便访问不存在的项产生KeyError。用get就返回空
>>> d = {}
>>> d['name']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'name'
>>> print d.get('name')
None
setdefault
setdefault:就是设定一个默认的键值对,如果原字典已经设置了,那么就不会采用默认的键值对,如果原子典没有,那么显然会添上默认的键值对。
>>> d = {}
>>> d.setdefault('name', 'ethan') # 返回设定的默认值 'ethan'
'ethan'
>>> d # d 被更新
{'name': 'ethan'}
>>> d['age'] = 20
>>> d
{'age': 20, 'name': 'ethan'}
>>> d.setdefault('age', 18) # age 已存在,返回已有的值,不会更新字典
20
>>> d
{'age': 20, 'name': 'ethan'}
update
update: 将一个字典添加到原字典,如果存在相同的键则会进行覆盖。
items/iteritems
items 方法将所有的字典项以列表形式返回,这些列表项的每一项都来自于(键,值)。我们也经常使用这个方法来对字典进行遍历。
iteritems 的作用大致相同,但会返回一个迭代器对象而不是列表,同样,我们也可以使用这个方法来对字典进行遍历,而且这也是推荐的做法.
推荐的做法在前面已经阐述。
keys/iterkeys 与values/itervalues
keys 方法将字典的键以列表形式返回,iterkeys 则返回针对键的迭代器。
values 方法将字典的值以列表形式返回,itervalues 则返回针对值的迭代器。
pop
移除字典中某个键值对,并返回给定的键的值
popitem随机移除某个键值对
对 元素为字典的列表 排序
就是说一个列表中有很多个字典,然后你要对这些字典进行排序。
students = [
{'name': 'john', 'score': 'B', 'age': 15},
{'name': 'jane', 'score': 'A', 'age': 12},
{'name': 'dave', 'score': 'B', 'age': 10},
{'name': 'ethan', 'score': 'C', 'age': 20},
{'name': 'peter', 'score': 'B', 'age': 20},
{'name': 'mike', 'score': 'C', 'age': 16}
]
- 按score从小到大排序
>>> sorted(students, key=lambda stu: stu['score'])
#返回的字典的键值对先后顺序与下面不一样。然而并没有什么关系,为了简便,不改了。
[{'age': 12, 'name': 'jane', 'score': 'A'},
{'age': 15, 'name': 'john', 'score': 'B'},
{'age': 10, 'name': 'dave', 'score': 'B'},
{'age': 20, 'name': 'peter', 'score': 'B'},
{'age': 20, 'name': 'ethan', 'score': 'C'},
{'age': 16, 'name': 'mike', 'score': 'C'}]
- 按 score 从大到小排序
>>> sorted(students, key=lambda stu: stu['score'], reverse=True) # reverse 参数
- 按 score 从小到大,再按 age 从小到大
sorted(students, key=lambda stu: (stu['score'], stu['age']))
- 按 score 从小到大,再按 age 从大到小
sorted(students, key=lambda stu: (stu['score'], -stu['age']))
集合
一句话,集合也用{ }, 它是一组key的集合,没有value。特性就是key不能重复!
>>> se = {'a',1}
>>> se
set(['a', 1])
- 遍历
仍旧是for e in s: 结构呗 - 添加
add() 方法
>>> s = {'a', 'b', 'c', 'a', 'd', 'b'}
>>> s.add('e') #没效果
>>> s
set(['a', 'c', 'b', 'e', 'd'])
>>> s.add(4)
>>> s
set(['a', 'c', 'b', 4, 'd', 'e'])
- 删除
remove() - 子集判断
set.issubset(subset)
交/并/差
分别是 & | -
>>> s1 = {1, 2, 3, 4, 5, 6}
>>> s2 = {3, 6, 9, 10, 12}
>>> s3 = {2, 3, 4}
>>> s1 & s2 # 交集
set([3, 6])
>>> s1 | s2 # 并集
set([1, 2, 3, 4, 5, 6, 9, 10, 12])
>>> s1 - s2 # 差集
set([1, 2, 4, 5])